ox 1.8.1 → 1.8.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 (152) hide show
  1. package/CHANGELOG.md +53 -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 +7 -4
  22. package/dist/core/Transaction.d.ts.map +1 -1
  23. package/dist/core/Transaction.js +8 -0
  24. package/dist/core/Transaction.js.map +1 -1
  25. package/dist/core/TransactionRequest.d.ts +8 -5
  26. package/dist/core/TransactionRequest.d.ts.map +1 -1
  27. package/dist/core/TransactionRequest.js +11 -3
  28. package/dist/core/TransactionRequest.js.map +1 -1
  29. package/dist/core/TxEnvelope.d.ts +4 -2
  30. package/dist/core/TxEnvelope.d.ts.map +1 -1
  31. package/dist/core/TxEnvelope.js +11 -2
  32. package/dist/core/TxEnvelope.js.map +1 -1
  33. package/dist/core/TxEnvelopeEip8141.d.ts +22 -11
  34. package/dist/core/TxEnvelopeEip8141.d.ts.map +1 -1
  35. package/dist/core/TxEnvelopeEip8141.js +45 -16
  36. package/dist/core/TxEnvelopeEip8141.js.map +1 -1
  37. package/dist/core/internal/frameNonce.d.ts +10 -0
  38. package/dist/core/internal/frameNonce.d.ts.map +1 -0
  39. package/dist/core/internal/frameNonce.js +45 -0
  40. package/dist/core/internal/frameNonce.js.map +1 -0
  41. package/dist/core/internal/rpcSchemas/eth.d.ts +16 -4
  42. package/dist/core/internal/rpcSchemas/eth.d.ts.map +1 -1
  43. package/dist/index.d.ts +21 -5
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +21 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/zod/Block.d.ts +52 -37
  48. package/dist/zod/Block.d.ts.map +1 -1
  49. package/dist/zod/Frame.d.ts +14 -14
  50. package/dist/zod/Frame.js +5 -5
  51. package/dist/zod/Frame.js.map +1 -1
  52. package/dist/zod/FrameReceipt.d.ts +42 -2
  53. package/dist/zod/FrameReceipt.d.ts.map +1 -1
  54. package/dist/zod/FrameReceipt.js +11 -1
  55. package/dist/zod/FrameReceipt.js.map +1 -1
  56. package/dist/zod/FrameRequest.d.ts +40 -0
  57. package/dist/zod/FrameRequest.d.ts.map +1 -0
  58. package/dist/zod/FrameRequest.js +37 -0
  59. package/dist/zod/FrameRequest.js.map +1 -0
  60. package/dist/zod/FrameSignature.d.ts +21 -13
  61. package/dist/zod/FrameSignature.d.ts.map +1 -1
  62. package/dist/zod/FrameSignature.js +10 -7
  63. package/dist/zod/FrameSignature.js.map +1 -1
  64. package/dist/zod/RpcSchema.d.ts +470 -265
  65. package/dist/zod/RpcSchema.d.ts.map +1 -1
  66. package/dist/zod/Transaction.d.ts +104 -74
  67. package/dist/zod/Transaction.d.ts.map +1 -1
  68. package/dist/zod/Transaction.js +22 -15
  69. package/dist/zod/Transaction.js.map +1 -1
  70. package/dist/zod/TransactionEnvelope.d.ts +60 -34
  71. package/dist/zod/TransactionEnvelope.d.ts.map +1 -1
  72. package/dist/zod/TransactionReceipt.d.ts +42 -2
  73. package/dist/zod/TransactionReceipt.d.ts.map +1 -1
  74. package/dist/zod/TransactionRequest.d.ts +31 -21
  75. package/dist/zod/TransactionRequest.d.ts.map +1 -1
  76. package/dist/zod/TransactionRequest.js +10 -4
  77. package/dist/zod/TransactionRequest.js.map +1 -1
  78. package/dist/zod/TxEnvelopeEip8141.d.ts +44 -25
  79. package/dist/zod/TxEnvelopeEip8141.d.ts.map +1 -1
  80. package/dist/zod/TxEnvelopeEip8141.js +2 -0
  81. package/dist/zod/TxEnvelopeEip8141.js.map +1 -1
  82. package/dist/zod/internal/Frame.d.ts +8 -0
  83. package/dist/zod/internal/Frame.d.ts.map +1 -1
  84. package/dist/zod/internal/Frame.js +29 -0
  85. package/dist/zod/internal/Frame.js.map +1 -1
  86. package/dist/zod/internal/rpcSchemas/Eth.d.ts +472 -267
  87. package/dist/zod/internal/rpcSchemas/Eth.d.ts.map +1 -1
  88. package/dist/zod/internal/rpcSchemas/Eth.js +9 -0
  89. package/dist/zod/internal/rpcSchemas/Eth.js.map +1 -1
  90. package/dist/zod/internal/rpcSchemas/Wallet.d.ts +51 -21
  91. package/dist/zod/internal/rpcSchemas/Wallet.d.ts.map +1 -1
  92. package/dist/zod/tempo/RpcSchemaTempo.d.ts +68 -48
  93. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  94. package/dist/zod/tempo/Transaction.d.ts +52 -37
  95. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  96. package/dist/zod/z.d.ts +1 -0
  97. package/dist/zod/z.d.ts.map +1 -1
  98. package/dist/zod/z.js +1 -0
  99. package/dist/zod/z.js.map +1 -1
  100. package/package.json +11 -1
  101. package/src/core/Frame.ts +41 -33
  102. package/src/core/FrameReceipt.ts +30 -16
  103. package/src/core/FrameRequest.ts +78 -0
  104. package/src/core/FrameSignature.ts +64 -34
  105. package/src/core/Siwe.ts +21 -13
  106. package/src/core/Transaction.ts +52 -24
  107. package/src/core/TransactionRequest.ts +21 -7
  108. package/src/core/TxEnvelope.ts +16 -3
  109. package/src/core/TxEnvelopeEip8141.ts +69 -21
  110. package/src/core/_test/AbiConstructor.test.ts +2 -0
  111. package/src/core/_test/Frame.test-d.ts +16 -7
  112. package/src/core/_test/Frame.test.ts +52 -24
  113. package/src/core/_test/FrameReceipt.test.ts +15 -9
  114. package/src/core/_test/FrameRequest.test-d.ts +16 -0
  115. package/src/core/_test/FrameRequest.test.ts +41 -0
  116. package/src/core/_test/FrameRpc.test.ts +131 -0
  117. package/src/core/_test/FrameSignature.test-d.ts +20 -0
  118. package/src/core/_test/FrameSignature.test.ts +132 -11
  119. package/src/core/_test/RpcSchema.test-d.ts +45 -0
  120. package/src/core/_test/Siwe.test.ts +147 -0
  121. package/src/core/_test/TransactionEnvelope.test-d.ts +27 -0
  122. package/src/core/_test/TransactionEnvelope.test.ts +27 -1
  123. package/src/core/_test/TransactionReceipt.test.ts +32 -6
  124. package/src/core/_test/TransactionRequest.test-d.ts +10 -1
  125. package/src/core/_test/TransactionRequest.test.ts +31 -2
  126. package/src/core/_test/TxEnvelopeEip8141.test-d.ts +29 -2
  127. package/src/core/_test/TxEnvelopeEip8141.test.ts +548 -55
  128. package/src/core/_test/index.test.ts +1 -0
  129. package/src/core/internal/frameNonce.ts +61 -0
  130. package/src/core/internal/rpcSchemas/eth.ts +13 -4
  131. package/src/index.ts +22 -5
  132. package/src/version.ts +1 -1
  133. package/src/zod/Frame.ts +5 -5
  134. package/src/zod/FrameReceipt.ts +11 -1
  135. package/src/zod/FrameRequest.ts +46 -0
  136. package/src/zod/FrameSignature.ts +10 -7
  137. package/src/zod/Transaction.ts +46 -27
  138. package/src/zod/TransactionRequest.ts +33 -18
  139. package/src/zod/TxEnvelopeEip8141.ts +2 -0
  140. package/src/zod/_test/Frame.test.ts +13 -11
  141. package/src/zod/_test/FrameReceipt.test.ts +11 -4
  142. package/src/zod/_test/FrameRequest.test-d.ts +15 -0
  143. package/src/zod/_test/FrameRequest.test.ts +44 -0
  144. package/src/zod/_test/FrameSignature.test.ts +73 -9
  145. package/src/zod/_test/RpcSchema.test.ts +106 -0
  146. package/src/zod/_test/TransactionRequest.test.ts +61 -0
  147. package/src/zod/_test/TxEnvelopeEip8141.nonce.test.ts +174 -0
  148. package/src/zod/_test/TxEnvelopeEip8141.test-d.ts +29 -0
  149. package/src/zod/_test/TxEnvelopeEip8141.test.ts +3 -3
  150. package/src/zod/internal/Frame.ts +45 -0
  151. package/src/zod/internal/rpcSchemas/Eth.ts +20 -0
  152. package/src/zod/z.ts +1 -0
@@ -43,6 +43,7 @@ test('exports', () => {
43
43
  "Filter",
44
44
  "Frame",
45
45
  "FrameReceipt",
46
+ "FrameRequest",
46
47
  "FrameSignature",
47
48
  "Hash",
48
49
  "HdKey",
@@ -0,0 +1,61 @@
1
+ import * as Errors from '../Errors.js'
2
+ import * as Hex from '../Hex.js'
3
+ import * as Quantity from './quantity.js'
4
+
5
+ export function assert(keys: readonly bigint[], nonce?: bigint): void {
6
+ if (!Array.isArray(keys) || keys.length < 1 || keys.length > 16)
7
+ throw new InvalidError('Expected between 1 and 16 nonce keys.')
8
+ for (const [index, key] of keys.entries()) {
9
+ if (typeof key !== 'bigint' || key < 0n || key >= 2n ** 256n)
10
+ throw new InvalidError('Nonce keys must be unsigned 256-bit integers.')
11
+ if (index > 0 && key <= keys[index - 1]!)
12
+ throw new InvalidError('Nonce keys must be strictly increasing.')
13
+ }
14
+ if (keys.length > 1 && keys[0] === 0n)
15
+ throw new InvalidError(
16
+ 'The zero nonce key cannot be combined with other keys.',
17
+ )
18
+ if (
19
+ nonce !== undefined &&
20
+ (typeof nonce !== 'bigint' || nonce < 0n || nonce >= 2n ** 64n - 1n)
21
+ )
22
+ throw new InvalidError('Nonce must be less than 2^64 - 1 and nonnegative.')
23
+ }
24
+
25
+ export function fromRpc(
26
+ keys: readonly Hex.Hex[],
27
+ nonce?: Hex.Hex,
28
+ ): readonly bigint[] {
29
+ if (!Array.isArray(keys)) throw new InvalidError('Expected a nonce key list.')
30
+ const integer = (value: Hex.Hex): bigint => {
31
+ if (
32
+ typeof value !== 'string' ||
33
+ !/^0x(?:0|[1-9a-fA-F][0-9a-fA-F]*)$/.test(value)
34
+ )
35
+ throw new InvalidError('Expected a canonical RPC nonce quantity.')
36
+ return Hex.toBigInt(value)
37
+ }
38
+ const decoded = keys.map(integer)
39
+ assert(decoded, nonce === undefined ? undefined : integer(nonce))
40
+ return decoded
41
+ }
42
+
43
+ export function toRpc(
44
+ keys: readonly (Hex.Hex | bigint | number)[],
45
+ nonce?: Hex.Hex | bigint | number,
46
+ ): readonly Hex.Hex[] {
47
+ if (!Array.isArray(keys)) throw new InvalidError('Expected a nonce key list.')
48
+ const encoded = keys.map((key) => Quantity.fromNumberish(key))
49
+ fromRpc(
50
+ encoded,
51
+ nonce === undefined ? undefined : Quantity.fromNumberish(nonce),
52
+ )
53
+ return encoded
54
+ }
55
+
56
+ export class InvalidError extends Errors.BaseError {
57
+ override readonly name = 'FrameNonce.InvalidError'
58
+ constructor(reason: string) {
59
+ super(reason)
60
+ }
61
+ }
@@ -4,6 +4,7 @@ import type * as Block from '../../Block.js'
4
4
  import type * as BlockOverrides from '../../BlockOverrides.js'
5
5
  import type * as Fee from '../../Fee.js'
6
6
  import type * as Filter from '../../Filter.js'
7
+ import type * as FrameReceipt from '../../FrameReceipt.js'
7
8
  import type * as Hex from '../../Hex.js'
8
9
  import type * as Log from '../../Log.js'
9
10
  import type * as RpcSchema from '../../RpcSchema.js'
@@ -11,6 +12,7 @@ import type * as StateOverrides from '../../StateOverrides.js'
11
12
  import type * as Transaction from '../../Transaction.js'
12
13
  import type * as TransactionReceipt from '../../TransactionReceipt.js'
13
14
  import type * as TransactionRequest from '../../TransactionRequest.js'
15
+ import type * as TxEnvelope from '../../TxEnvelope.js'
14
16
 
15
17
  /**
16
18
  * Union of all JSON-RPC Methods for the `eth_` namespace.
@@ -219,12 +221,12 @@ export type Eth = RpcSchema.From<
219
221
  ReturnType: Fee.FeeHistoryRpc
220
222
  }
221
223
  /**
222
- * Fills the defaults (nonce, gas, gasPrice, or 1559 fields) on a given unsigned transaction, and returns the unsigned transaction along with its raw form
224
+ * Fills transaction defaults and returns the unsigned transaction.
223
225
  *
224
226
  * @example
225
227
  * ```
226
228
  * request({ method: 'eth_fillTransaction', params: [{ from: '0x...', to: '0x...', value: '0x...' }] })
227
- * // { raw: '0x...', tx: { ... } }
229
+ * // { tx: { ... } }
228
230
  * ```
229
231
  */
230
232
  | {
@@ -234,8 +236,8 @@ export type Eth = RpcSchema.From<
234
236
  }
235
237
  ReturnType: {
236
238
  capabilities?: Record<string, unknown> | undefined
237
- raw: Hex.Hex
238
- tx: Transaction.Rpc
239
+ raw?: Hex.Hex | undefined
240
+ tx: TxEnvelope.Rpc & { from: Address.Address }
239
241
  }
240
242
  }
241
243
  /**
@@ -769,6 +771,13 @@ export type Eth = RpcSchema.From<
769
771
  message: string
770
772
  }
771
773
  | undefined
774
+ frameResults?:
775
+ | readonly (FrameReceipt.Rpc & {
776
+ error?: { code: number; message: string } | undefined
777
+ returnData: Hex.Hex
778
+ })[]
779
+ | undefined
780
+ payer?: Address.Address | undefined
772
781
  logs?: readonly Log.Rpc[] | undefined
773
782
  gasUsed: Hex.Hex
774
783
  returnData: Hex.Hex
package/src/index.ts CHANGED
@@ -1618,13 +1618,13 @@ export * as Filter from './core/Filter.js'
1618
1618
  * import { Frame } from 'ox'
1619
1619
  *
1620
1620
  * const frame = Frame.from({
1621
+ * executionGas: 50_000n,
1621
1622
  * flags: 'approveExecutionAndPayment',
1622
- * gas: 50_000n,
1623
1623
  * mode: 'verify'
1624
1624
  * })
1625
1625
  * ```
1626
1626
  *
1627
- * @category Transaction Envelopes
1627
+ * @category Frames (EIP-8141)
1628
1628
  */
1629
1629
  export * as Frame from './core/Frame.js'
1630
1630
 
@@ -1633,10 +1633,27 @@ export * as Frame from './core/Frame.js'
1633
1633
  *
1634
1634
  * Frame receipts include execution gas, state gas, logs, and execution status.
1635
1635
  *
1636
- * @category Execution Spec
1636
+ * @category Frames (EIP-8141)
1637
1637
  */
1638
1638
  export * as FrameReceipt from './core/FrameReceipt.js'
1639
1639
 
1640
+ /**
1641
+ * Convert EIP-8141 frame requests while preserving omitted gas limits for node estimation.
1642
+ *
1643
+ * @example
1644
+ * ```ts twoslash
1645
+ * import { FrameRequest } from 'ox'
1646
+ *
1647
+ * const frame = FrameRequest.toRpc({
1648
+ * mode: 'sender',
1649
+ * stateGas: 0n
1650
+ * })
1651
+ * ```
1652
+ *
1653
+ * @category Frames (EIP-8141)
1654
+ */
1655
+ export * as FrameRequest from './core/FrameRequest.js'
1656
+
1640
1657
  /**
1641
1658
  * Utilities for constructing, validating, and encoding [EIP-8141](https://eips.ethereum.org/EIPS/eip-8141) signature entries.
1642
1659
  *
@@ -1656,7 +1673,7 @@ export * as FrameReceipt from './core/FrameReceipt.js'
1656
1673
  * // @log: { payload: '0x', scheme: 'arbitrary', signature: '0xaabb' }
1657
1674
  * ```
1658
1675
  *
1659
- * @category Transaction Envelopes
1676
+ * @category Frames (EIP-8141)
1660
1677
  */
1661
1678
  export * as FrameSignature from './core/FrameSignature.js'
1662
1679
 
@@ -3580,7 +3597,7 @@ export * as TxEnvelopeEip7702 from './core/TxEnvelopeEip7702.js'
3580
3597
  *
3581
3598
  * const envelope = TxEnvelopeEip8141.from({
3582
3599
  * chainId: 1,
3583
- * frames: [{ gas: 50_000n, mode: 'sender' }],
3600
+ * frames: [{ executionGas: 50_000n, mode: 'sender' }],
3584
3601
  * sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
3585
3602
  * })
3586
3603
  * ```
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** @internal */
2
- export const version = '1.8.1'
2
+ export const version = '1.8.4'
package/src/zod/Frame.ts CHANGED
@@ -25,10 +25,10 @@ export const Decoded: z.ZodMiniType<core_Frame.Frame, core_Frame.Frame> = z
25
25
  export const Rpc = z
26
26
  .object({
27
27
  data: z_Hex.Hex,
28
- executionGasLimit: z_Hex.Hex,
29
- flags: z.number(),
30
- mode: z.number(),
31
- stateGasLimit: z_Hex.Hex,
28
+ executionGas: z_Hex.Hex,
29
+ flags: z_Hex.Hex,
30
+ mode: z_Hex.Hex,
31
+ stateGas: z_Hex.Hex,
32
32
  target: z.optional(z.nullable(z_Address.Address)),
33
33
  value: z_Hex.Hex,
34
34
  })
@@ -72,8 +72,8 @@ export const FrameToRpc = z.codec(Rpc, DecodedToRpc, {
72
72
  function fields<uint extends z.ZodMiniType>(uint: uint) {
73
73
  return {
74
74
  data: z.optional(z_Hex.Hex),
75
+ executionGas: z.optional(uint),
75
76
  flags: z.optional(Flags),
76
- gas: z.optional(uint),
77
77
  mode: z.optional(Mode),
78
78
  stateGas: z.optional(uint),
79
79
  to: z.optional(z_Address.Address),
@@ -11,17 +11,26 @@ import * as z from 'zod/mini'
11
11
 
12
12
  const frameLog = z.object({
13
13
  address: z_Address.Address,
14
+ blockHash: z.optional(z_Hex.Hex),
15
+ blockNumber: z.optional(quantityHex()),
16
+ blockTimestamp: z.optional(quantityHex()),
14
17
  data: z_Hex.Hex,
18
+ logIndex: z.optional(quantityHex()),
19
+ removed: z.optional(z.boolean()),
15
20
  topics: z.array(z_Hex.Hex),
21
+ transactionHash: z.optional(z_Hex.Hex),
22
+ transactionIndex: z.optional(quantityHex()),
16
23
  })
17
24
 
18
25
  const frameReceiptRpc = z.object({
19
26
  executionGasUsed: quantityHex(),
27
+ gasUsed: quantityHex(),
20
28
  logs: z.readonly(z.array(frameLog)),
21
29
  stateGasUsed: quantityHex(),
22
- status: z.union([z.literal(0), z.literal(1), z.literal(2)]),
30
+ status: z.enum(['0x0', '0x1', '0x2']),
23
31
  })
24
32
  const frameReceiptDecoded = z.object({
33
+ executionGasUsed: uintBigint(),
25
34
  gasUsed: uintBigint(),
26
35
  logs: z.readonly(z.array(frameLog)),
27
36
  stateGasUsed: uintBigint(),
@@ -38,6 +47,7 @@ export const FrameReceipt = z.codec(frameReceiptRpc, frameReceiptDecoded, {
38
47
  export const FrameReceiptToRpc = z.codec(
39
48
  frameReceiptRpc,
40
49
  z.extend(frameReceiptDecoded, {
50
+ executionGasUsed: uintBigintNumberish(),
41
51
  gasUsed: uintBigintNumberish(),
42
52
  stateGasUsed: uintBigintNumberish(),
43
53
  }),
@@ -0,0 +1,46 @@
1
+ /* eslint-disable jsdoc-js/require-jsdoc, jsdoc-js/require-description, jsdoc-js/require-example */
2
+ import * as core_FrameRequest from '../core/FrameRequest.js'
3
+ import * as z_Address from './Address.js'
4
+ import * as z_Frame from './Frame.js'
5
+ import * as z_Hex from './Hex.js'
6
+ import * as z from 'zod/mini'
7
+
8
+ const quantity = z_Hex.Hex.check(
9
+ z.refine(
10
+ (value) => /^0x(0|[1-9a-f][0-9a-f]*)$/.test(value),
11
+ 'Invalid RPC quantity',
12
+ ),
13
+ )
14
+
15
+ const rpc = z
16
+ .object({
17
+ data: z.optional(z_Hex.Hex),
18
+ executionGas: z.optional(quantity),
19
+ flags: z.optional(z_Hex.Hex),
20
+ mode: z_Hex.Hex,
21
+ stateGas: z.optional(quantity),
22
+ target: z.optional(z.nullable(z_Address.Address)),
23
+ value: z.optional(quantity),
24
+ })
25
+ .check(
26
+ z.refine((value) => {
27
+ try {
28
+ core_FrameRequest.fromRpc(value)
29
+ return true
30
+ } catch {
31
+ return false
32
+ }
33
+ }, 'Invalid frame request'),
34
+ )
35
+
36
+ /** Codec between RPC and decoded frame requests, preserving omitted gas limits. */
37
+ export const FrameRequest = z.codec(rpc, z_Frame.Decoded, {
38
+ decode: core_FrameRequest.fromRpc,
39
+ encode: core_FrameRequest.toRpc,
40
+ })
41
+
42
+ /** Encode-only frame request codec accepting numberish gas and value. */
43
+ export const FrameRequestToRpc = z.codec(rpc, z_Frame.DecodedToRpc, {
44
+ decode: core_FrameRequest.fromRpc,
45
+ encode: core_FrameRequest.toRpc,
46
+ })
@@ -24,7 +24,10 @@ export const Secp256k1 = z.object({
24
24
  payload: z.optional(z_Hex.Hex),
25
25
  scheme: z.union([z.literal(1), z.literal('secp256k1')]),
26
26
  signature: z.optional(
27
- z.object({ r: z_Hex.Hex, s: z_Hex.Hex, yParity: z.number() }),
27
+ z.union([
28
+ z_Hex.Hex,
29
+ z.object({ r: z_Hex.Hex, s: z_Hex.Hex, yParity: z.number() }),
30
+ ]),
28
31
  ),
29
32
  signer: z.optional(z_Address.Address),
30
33
  })
@@ -36,11 +39,11 @@ const p256 = {
36
39
  }
37
40
  /** P-256 frame signature schema, including unsigned placeholders. */
38
41
  export const P256 = z.union([
39
- z.object({ ...p256, publicKey, signature }),
42
+ z.object({ ...p256, publicKey, signature: z.union([z_Hex.Hex, signature]) }),
40
43
  z.object({
41
44
  ...p256,
42
45
  publicKey: z.optional(publicKey),
43
- signature: z.optional(z.undefined()),
46
+ signature: z.optional(z.literal('0x')),
44
47
  }),
45
48
  ])
46
49
 
@@ -55,10 +58,10 @@ export const Decoded: z.ZodMiniType<
55
58
  /** RPC frame signature schema. */
56
59
  export const Rpc = z
57
60
  .object({
58
- msg: z_Hex.Hex,
59
- scheme: z.union([z.literal(0), z.literal(1), z.literal(2)]),
60
- signature: z_Hex.Hex,
61
- signer: z.optional(z.nullable(z_Address.Address)),
61
+ msg: z.optional(z_Hex.Hex),
62
+ scheme: z.enum(['0x0', '0x1', '0x2']),
63
+ signature: z.optional(z_Hex.Hex),
64
+ signer: z.optional(z.union([z.literal('0x'), z_Address.Address])),
62
65
  })
63
66
  .check(
64
67
  z.refine((value) => {
@@ -4,7 +4,13 @@ import * as z_Address from './Address.js'
4
4
  import * as z_Authorization from './Authorization.js'
5
5
  import * as z_Frame from './Frame.js'
6
6
  import * as z_FrameSignature from './FrameSignature.js'
7
- import { chainId, chainIdToRpc } from './internal/Frame.js'
7
+ import {
8
+ chainId,
9
+ chainIdToRpc,
10
+ nonceKeys,
11
+ nonceKeysToRpc,
12
+ validNonce,
13
+ } from './internal/Frame.js'
8
14
  import * as z_Hex from './Hex.js'
9
15
  import * as z_Number from './Number.js'
10
16
  import * as z_Uint from './Uint.js'
@@ -142,55 +148,68 @@ export const PendingEip7702 = z.object(
142
148
  const Eip8141Type = type('0x6', 'eip8141')
143
149
 
144
150
  /** EIP-8141 transaction schema. */
145
- export const Eip8141 = z.object({
146
- ...eip8141Fields(z_Uint.Uint, chainId, z_Frame.Frame),
147
- blockHash: z_Hex.Hex,
148
- blockNumber: z_Uint.Uint,
149
- blockTimestamp: z.optional(z_Uint.Uint),
150
- transactionIndex: z_Number.Number,
151
- })
151
+ export const Eip8141 = z
152
+ .object({
153
+ ...eip8141Fields(z_Uint.Uint, chainId, z_Frame.Frame, nonceKeys),
154
+ blockHash: z_Hex.Hex,
155
+ blockNumber: z_Uint.Uint,
156
+ blockTimestamp: z.optional(z_Uint.Uint),
157
+ transactionIndex: z_Number.Number,
158
+ })
159
+ .check(z.refine(validNonce, 'Invalid keyed nonce'))
152
160
 
153
161
  /** Encode-only EIP-8141 transaction schema accepting numberish values. */
154
- export const Eip8141ToRpc = z.object({
155
- ...eip8141Fields(z_Uint.UintToRpc, chainIdToRpc, z_Frame.FrameToRpc),
156
- blockHash: z_Hex.Hex,
157
- blockNumber: z_Uint.UintToRpc,
158
- blockTimestamp: z.optional(z_Uint.UintToRpc),
159
- transactionIndex: z_Number.NumberToRpc,
160
- })
162
+ export const Eip8141ToRpc = z
163
+ .object({
164
+ ...eip8141Fields(
165
+ z_Uint.UintToRpc,
166
+ chainIdToRpc,
167
+ z_Frame.FrameToRpc,
168
+ nonceKeysToRpc,
169
+ ),
170
+ blockHash: z_Hex.Hex,
171
+ blockNumber: z_Uint.UintToRpc,
172
+ blockTimestamp: z.optional(z_Uint.UintToRpc),
173
+ transactionIndex: z_Number.NumberToRpc,
174
+ })
175
+ .check(z.refine(validNonce, 'Invalid keyed nonce'))
161
176
 
162
177
  /** Pending EIP-8141 transaction schema. */
163
- export const PendingEip8141 = z.object({
164
- ...eip8141Fields(z_Uint.Uint, chainId, z_Frame.Frame),
165
- blockHash: z.null(),
166
- blockNumber: z.null(),
167
- blockTimestamp: z.optional(z.null()),
168
- transactionIndex: z.null(),
169
- })
178
+ export const PendingEip8141 = z
179
+ .object({
180
+ ...eip8141Fields(z_Uint.Uint, chainId, z_Frame.Frame, nonceKeys),
181
+ blockHash: z.null(),
182
+ blockNumber: z.null(),
183
+ blockTimestamp: z.optional(z.null()),
184
+ transactionIndex: z.null(),
185
+ })
186
+ .check(z.refine(validNonce, 'Invalid keyed nonce'))
170
187
 
171
188
  function eip8141Fields<
172
189
  uint extends z.ZodMiniType,
173
190
  num extends z.ZodMiniType,
174
191
  frame extends z.ZodMiniType,
175
- >(uint: uint, num: num, frame: frame) {
192
+ keys extends z.ZodMiniType,
193
+ >(uint: uint, num: num, frame: frame, keys: keys) {
176
194
  return {
177
195
  blobVersionedHashes: z.readonly(z.array(z_Hex.Hex)),
178
196
  chainId: num,
179
197
  data: z.optional(z_Hex.Hex),
180
198
  frames: z.readonly(z.array(frame)),
181
199
  from: z_Address.Address,
182
- gas: uint,
200
+ gas: z.optional(uint),
183
201
  gasPrice: z.optional(uint),
184
202
  hash: z_Hex.Hex,
185
- input: z_Hex.Hex,
203
+ input: z.optional(z_Hex.Hex),
186
204
  maxFeePerBlobGas: uint,
187
205
  maxFeePerGas: uint,
188
206
  maxPriorityFeePerGas: uint,
189
207
  nonce: uint,
208
+ nonceKeys: z.optional(keys),
190
209
  signatures: z.readonly(z.array(z_FrameSignature.FrameSignature)),
191
- to: z.nullable(z_Address.Address),
210
+ to: z.optional(z.nullable(z_Address.Address)),
192
211
  type: Eip8141Type,
193
- value: uint,
212
+ value: z.optional(uint),
194
213
  }
195
214
  }
196
215
 
@@ -2,9 +2,10 @@
2
2
  import * as z_AccessList from './AccessList.js'
3
3
  import * as z_Address from './Address.js'
4
4
  import * as z_Authorization from './Authorization.js'
5
- import * as z_Frame from './Frame.js'
5
+ import * as z_FrameRequest from './FrameRequest.js'
6
6
  import * as z_FrameSignature from './FrameSignature.js'
7
7
  import * as z_Hex from './Hex.js'
8
+ import { nonceKeys, nonceKeysToRpc, validNonce } from './internal/Frame.js'
8
9
  import * as z_Number from './Number.js'
9
10
  import * as z_Uint from './Uint.js'
10
11
  import * as z from 'zod/mini'
@@ -33,31 +34,44 @@ const type = z.codec(z.string(), z.string(), {
33
34
  })
34
35
 
35
36
  /** Transaction request schema. */
36
- export const TransactionRequest = z.object(
37
- fields(
38
- z_Uint.Uint,
39
- z_Number.Number,
40
- z_Authorization.ListSigned,
41
- z_Frame.Frame,
42
- ),
43
- )
37
+ export const TransactionRequest = z
38
+ .object(
39
+ fields(
40
+ z_Uint.Uint,
41
+ z_Number.Number,
42
+ z_Authorization.ListSigned,
43
+ z_FrameRequest.FrameRequest,
44
+ nonceKeys,
45
+ ),
46
+ )
47
+ .check(z.refine(validNonce, 'Invalid keyed nonce'))
44
48
 
45
49
  /** Encode-only transaction request schema accepting numberish `toRpc` inputs. */
46
- export const TransactionRequestToRpc = z.object(
47
- fields(
48
- z_Uint.UintToRpc,
49
- z_Number.NumberToRpc,
50
- z_Authorization.ListSignedToRpc,
51
- z_Frame.FrameToRpc,
52
- ),
53
- )
50
+ export const TransactionRequestToRpc = z
51
+ .object(
52
+ fields(
53
+ z_Uint.UintToRpc,
54
+ z_Number.NumberToRpc,
55
+ z_Authorization.ListSignedToRpc,
56
+ z_FrameRequest.FrameRequestToRpc,
57
+ nonceKeysToRpc,
58
+ ),
59
+ )
60
+ .check(z.refine(validNonce, 'Invalid keyed nonce'))
54
61
 
55
62
  function fields<
56
63
  uint extends z.ZodMiniType,
57
64
  num extends z.ZodMiniType,
58
65
  authorizationList extends z.ZodMiniType,
59
66
  frame extends z.ZodMiniType,
60
- >(uint: uint, num: num, authorizationList: authorizationList, frame: frame) {
67
+ keys extends z.ZodMiniType,
68
+ >(
69
+ uint: uint,
70
+ num: num,
71
+ authorizationList: authorizationList,
72
+ frame: frame,
73
+ keys: keys,
74
+ ) {
61
75
  return {
62
76
  accessList: z.optional(z_AccessList.AccessList),
63
77
  authorizationList: z.optional(authorizationList),
@@ -74,6 +88,7 @@ function fields<
74
88
  maxFeePerGas: z.optional(uint),
75
89
  maxPriorityFeePerGas: z.optional(uint),
76
90
  nonce: z.optional(uint),
91
+ nonceKeys: z.optional(keys),
77
92
  signatures: z.optional(
78
93
  z.readonly(z.array(z_FrameSignature.FrameSignature)),
79
94
  ),
@@ -25,6 +25,7 @@ export const Rpc = z
25
25
  maxFeePerGas: z_Hex.Hex,
26
26
  maxPriorityFeePerGas: z_Hex.Hex,
27
27
  nonce: z_Hex.Hex,
28
+ nonceKeys: z.optional(z.readonly(z.array(z_Hex.Hex))),
28
29
  signatures: z.readonly(z.array(z_FrameSignature.Rpc)),
29
30
  type: z.literal('0x6'),
30
31
  })
@@ -94,6 +95,7 @@ function fields<
94
95
  maxFeePerGas: z.optional(uint),
95
96
  maxPriorityFeePerGas: z.optional(uint),
96
97
  nonce: z.optional(uint),
98
+ nonceKeys: z.optional(z.readonly(z.array(uint))),
97
99
  sender: z_Address.Address,
98
100
  sidecars: z.optional(z_TxEnvelopeEip4844.Sidecars),
99
101
  signatures: z.optional(z.readonly(z.array(z_FrameSignature.Decoded))),
@@ -5,25 +5,25 @@ import { describe, expect, test } from 'vp/test'
5
5
  describe('Frame', () => {
6
6
  test('decodes RPC budgets and encodes named flags', () => {
7
7
  const frame = Frame.from({
8
+ executionGas: 50_000n,
8
9
  flags: 'approveExecutionAndPayment',
9
- gas: 50_000n,
10
10
  mode: 'verify',
11
11
  to: '0x1111111111111111111111111111111111111111',
12
12
  })
13
13
  const rpc = z.encode(z.Frame.Frame, frame)
14
14
  expect(rpc).toEqual({
15
15
  data: '0x',
16
- executionGasLimit: '0xc350',
17
- flags: 3,
18
- mode: 1,
19
- stateGasLimit: '0x0',
16
+ executionGas: '0xc350',
17
+ flags: '0x3',
18
+ mode: '0x1',
19
+ stateGas: '0x0',
20
20
  target: '0x1111111111111111111111111111111111111111',
21
21
  value: '0x0',
22
22
  })
23
23
  expect(z.decode(z.Frame.Frame, rpc)).toEqual({
24
24
  data: '0x',
25
+ executionGas: 50_000n,
25
26
  flags: 3,
26
- gas: 50_000n,
27
27
  mode: 1,
28
28
  stateGas: 0n,
29
29
  to: '0x1111111111111111111111111111111111111111',
@@ -32,12 +32,14 @@ describe('Frame', () => {
32
32
  })
33
33
  test('rejects invalid mode and budget', () => {
34
34
  expect(z.safeParse(z.Frame.Decoded, { mode: 3 }).success).toBe(false)
35
- expect(z.safeParse(z.Frame.Decoded, { gas: -1n }).success).toBe(false)
35
+ expect(z.safeParse(z.Frame.Decoded, { executionGas: -1n }).success).toBe(
36
+ false,
37
+ )
36
38
  })
37
39
  test('encodes numberish values', () => {
38
40
  expect(
39
- z.encode(z.Frame.FrameToRpc, { gas: '0xc350', stateGas: 0 })
40
- .executionGasLimit,
41
+ z.encode(z.Frame.FrameToRpc, { executionGas: '0xc350', stateGas: 0 })
42
+ .executionGas,
41
43
  ).toBe('0xc350')
42
44
  })
43
45
  })
@@ -46,9 +48,9 @@ describe('FrameToRpc validation', () => {
46
48
  test.each([
47
49
  { mode: 3 },
48
50
  { flags: 8 },
49
- { gas: 2n ** 64n },
51
+ { executionGas: 2n ** 64n },
50
52
  { stateGas: -1 },
51
- { gas: '0x10000000000000000' },
53
+ { executionGas: '0x10000000000000000' },
52
54
  ])('rejects invalid frame %#', (frame) => {
53
55
  expect(
54
56
  z.safeEncode(z.Frame.FrameToRpc, frame as Frame.toRpc.Input).success,