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
@@ -245,7 +245,7 @@ describe('assert', () => {
245
245
  expect(() =>
246
246
  TxEnvelopeEip8141.assert({
247
247
  chainId: 1,
248
- frames: [{ gas: 2n ** 64n - 1n }, { stateGas: 1n }],
248
+ frames: [{ executionGas: 2n ** 64n - 1n }, { stateGas: 1n }],
249
249
  sender: accounts[0].address,
250
250
  }),
251
251
  ).toThrowErrorMatchingInlineSnapshot(
@@ -257,7 +257,7 @@ describe('assert', () => {
257
257
  expect(() =>
258
258
  TxEnvelopeEip8141.assert({
259
259
  chainId: 1,
260
- frames: [{ gas: 16_777_216n }],
260
+ frames: [{ executionGas: 16_777_216n }],
261
261
  sender: accounts[0].address,
262
262
  }),
263
263
  ).toThrowErrorMatchingInlineSnapshot(
@@ -354,8 +354,8 @@ describe('deserialize', () => {
354
354
  "frames": [
355
355
  {
356
356
  "data": "0x",
357
+ "executionGas": 0n,
357
358
  "flags": 0,
358
- "gas": 0n,
359
359
  "mode": 0,
360
360
  "stateGas": 0n,
361
361
  "value": 0n,
@@ -450,7 +450,7 @@ describe('from', () => {
450
450
  expect(
451
451
  TxEnvelopeEip8141.from({
452
452
  chainId: 1,
453
- frames: [{ gas: 50000n }],
453
+ frames: [{ executionGas: 50000n }],
454
454
  sender: accounts[0].address,
455
455
  }),
456
456
  ).toMatchInlineSnapshot(`
@@ -458,7 +458,7 @@ describe('from', () => {
458
458
  "chainId": 1,
459
459
  "frames": [
460
460
  {
461
- "gas": 50000n,
461
+ "executionGas": 50000n,
462
462
  },
463
463
  ],
464
464
  "sender": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
@@ -479,8 +479,8 @@ describe('from', () => {
479
479
  "frames": [
480
480
  {
481
481
  "data": "0x",
482
+ "executionGas": 0n,
482
483
  "flags": 0,
483
- "gas": 0n,
484
484
  "mode": 0,
485
485
  "stateGas": 0n,
486
486
  "value": 0n,
@@ -499,16 +499,43 @@ describe('from', () => {
499
499
  })
500
500
 
501
501
  describe('getSignPayload', () => {
502
+ test.each([
503
+ { scheme: 'secp256k1', signature: '0x' },
504
+ { scheme: 'p256', signature: '0x' },
505
+ ] as const)(
506
+ 'empty $scheme placeholders preserve the signing hash',
507
+ (entry) => {
508
+ const { signature: _, ...unsigned } = entry
509
+ const envelope = {
510
+ chainId: 1,
511
+ frames: [{ executionGas: 50_000n, mode: 'sender' }],
512
+ sender: accounts[0].address,
513
+ signatures: [unsigned],
514
+ } as const
515
+ const input = {
516
+ ...envelope,
517
+ signatures: [entry],
518
+ } as const
519
+ expect(TxEnvelopeEip8141.getSignPayload(input)).toBe(
520
+ TxEnvelopeEip8141.getSignPayload(envelope),
521
+ )
522
+ expect(TxEnvelopeEip8141.serialize(input)).toBe(
523
+ TxEnvelopeEip8141.serialize(envelope),
524
+ )
525
+ expect(input.signatures[0].signature).toBe('0x')
526
+ },
527
+ )
528
+
502
529
  test('omitted nested defaults preserve the signing hash and encoding', () => {
503
530
  const envelope = TxEnvelopeEip8141.from({
504
531
  chainId: 1,
505
- frames: [{ gas: 50_000n, mode: 'sender' }],
532
+ frames: [{ executionGas: 50_000n, mode: 'sender' }],
506
533
  sender: accounts[0].address,
507
534
  signatures: [{ scheme: 'secp256k1' }],
508
535
  })
509
536
  const explicit = TxEnvelopeEip8141.from({
510
537
  ...envelope,
511
- frames: [Frame.from({ gas: 50_000n, mode: 'sender' })],
538
+ frames: [Frame.from({ executionGas: 50_000n, mode: 'sender' })],
512
539
  signatures: [FrameSignature.from({ scheme: 'secp256k1' })],
513
540
  })
514
541
  expect(TxEnvelopeEip8141.getSignPayload(envelope)).toBe(
@@ -630,26 +657,26 @@ describe('serialize', () => {
630
657
  const request = TransactionRequest.toRpc({
631
658
  frames: [
632
659
  Frame.from({
660
+ executionGas: 50_000n,
633
661
  flags: 'approveExecutionAndPayment',
634
- gas: 50_000n,
635
662
  mode: 'verify',
663
+ stateGas: 0n,
664
+ }),
665
+ Frame.from({
666
+ executionGas: 50_000n,
667
+ mode: 'sender',
668
+ stateGas: 0n,
669
+ to: target,
670
+ value: 1n,
636
671
  }),
637
- Frame.from({ gas: 50_000n, mode: 'sender', to: target, value: 1n }),
638
672
  ],
639
673
  from: sender,
640
674
  signatures: [{ scheme: 'secp256k1' }],
641
- // Nethermind's simulation mapping requires an outer recipient before processing frames.
642
- to: sender,
643
675
  type: 'eip8141',
644
676
  })
645
- // TODO: remove once migrated to reth or anvil.
646
- // Nethermind validates signatures when filling gas, before the transaction can be signed.
647
- await expect(
648
- rpc.request({ method: 'eth_fillTransaction', params: [request] }),
649
- ).rejects.toThrow('frame transaction signature has the wrong length')
650
677
  const { tx } = await rpc.request({
651
678
  method: 'eth_fillTransaction',
652
- params: [{ ...request, gas: Hex.fromNumber(100_000n) }],
679
+ params: [request],
653
680
  })
654
681
  expect(tx.type).toBe('0x6')
655
682
  if (tx.type !== '0x6' || !tx.frames)
@@ -658,7 +685,6 @@ describe('serialize', () => {
658
685
  expect(tx.nonce).toBe(nonce)
659
686
  expect(tx.frames).toEqual(request.frames)
660
687
  expect(tx.signatures).toEqual(request.signatures)
661
- expect(Hex.toBigInt(tx.gas)).toBe(100_000n)
662
688
  expect(Hex.toBigInt(tx.maxFeePerGas)).toBeGreaterThan(0n)
663
689
  expect(Hex.toBigInt(tx.maxPriorityFeePerGas)).toBeGreaterThanOrEqual(0n)
664
690
  expect(Hex.toBigInt(tx.maxFeePerGas)).toBeGreaterThanOrEqual(
@@ -728,14 +754,19 @@ describe('serialize', () => {
728
754
  chainId: 8141,
729
755
  frames: [
730
756
  Frame.from({
757
+ executionGas: 50_000n,
731
758
  flags: 'approveExecutionAndPayment',
732
- gas: 50_000n,
733
759
  mode: 'verify',
734
760
  }),
735
- Frame.from({ gas: 50_000n, mode: 'sender', to: target, value: 1n }),
761
+ Frame.from({
762
+ executionGas: 50_000n,
763
+ mode: 'sender',
764
+ to: target,
765
+ value: 1n,
766
+ }),
736
767
  Frame.from({
737
768
  data: '0xdeadbeef',
738
- gas: 50_000n,
769
+ executionGas: 50_000n,
739
770
  mode: 'sender',
740
771
  to: '0x0000000000000000000000000000000000000004',
741
772
  }),
@@ -756,14 +787,12 @@ describe('serialize', () => {
756
787
  })
757
788
  const request = TransactionRequest.toRpc({
758
789
  ...TransactionEnvelope.toTransactionRequest(signed),
759
- // Nethermind's simulation mapping requires an outer recipient before processing frames.
760
- to: sender,
761
790
  })
762
791
  const result = await rpc.request({
763
792
  method,
764
793
  params: [request, 'latest'],
765
794
  })
766
- // Frame return data is not exposed by Nethermind's transaction-level call result.
795
+ // Transaction-level calls do not expose individual frame return data.
767
796
  if (method === 'eth_call') expect(result).toBe('0x')
768
797
  else {
769
798
  // Estimation includes all signed frame budgets plus intrinsic gas.
@@ -774,11 +803,14 @@ describe('serialize', () => {
774
803
  rpc.request({
775
804
  method,
776
805
  params: [
777
- { ...request, frames: [{ ...request.frames![0]!, mode: 255 }] },
806
+ {
807
+ ...request,
808
+ frames: [{ ...request.frames![0]!, mode: '0xff' }],
809
+ },
778
810
  'latest',
779
811
  ],
780
812
  }),
781
- ).rejects.toThrow('frame mode')
813
+ ).rejects.toThrow('Invalid params')
782
814
  expect(
783
815
  await rpc.request({
784
816
  method: 'eth_getBalance',
@@ -806,11 +838,16 @@ describe('serialize', () => {
806
838
  chainId: 8141,
807
839
  frames: [
808
840
  Frame.from({
841
+ executionGas: 50_000n,
809
842
  flags: 'approveExecutionAndPayment',
810
- gas: 50_000n,
811
843
  mode: 'verify',
812
844
  }),
813
- Frame.from({ gas: 50_000n, mode: 'sender', to: target, value: 1n }),
845
+ Frame.from({
846
+ executionGas: 50_000n,
847
+ mode: 'sender',
848
+ to: target,
849
+ value: 1n,
850
+ }),
814
851
  ],
815
852
  maxFeePerGas: 10_000_000_000n,
816
853
  maxPriorityFeePerGas: 1_000_000_000n,
@@ -840,10 +877,12 @@ describe('serialize', () => {
840
877
  })
841
878
  expect(hash).toBe(TransactionEnvelope.hash(signed))
842
879
  expect(
843
- TransactionRequest.toEnvelope(
844
- TransactionEnvelope.toTransactionRequest(signed),
880
+ TransactionEnvelope.serialize(
881
+ TransactionRequest.toEnvelope(
882
+ TransactionEnvelope.toTransactionRequest(signed),
883
+ ),
845
884
  ),
846
- ).toEqual(signed)
885
+ ).toBe(serialized)
847
886
  expect(TxEnvelopeEip8141.toRpc(signed)).toMatchObject(
848
887
  TransactionRequest.toRpc(
849
888
  TransactionEnvelope.toTransactionRequest(signed),
@@ -939,18 +978,18 @@ describe('serialize', () => {
939
978
  chainId: 8141,
940
979
  frames: [
941
980
  Frame.from({
981
+ executionGas: 20_000n,
942
982
  flags: 'approveExecution',
943
- gas: 50_000n,
944
983
  mode: 'verify',
945
984
  }),
946
985
  Frame.from({
986
+ executionGas: 20_000n,
947
987
  flags: 'approvePayment',
948
- gas: 50_000n,
949
988
  mode: 'verify',
950
989
  to: accounts[1].address,
951
990
  }),
952
991
  Frame.from({
953
- gas: 50_000n,
992
+ executionGas: 20_000n,
954
993
  mode: 'sender',
955
994
  to: accounts[1].address,
956
995
  value: 1n,
@@ -1045,25 +1084,25 @@ describe('serialize', () => {
1045
1084
  chainId: 8141,
1046
1085
  frames: [
1047
1086
  Frame.from({
1087
+ executionGas: 50_000n,
1048
1088
  flags: 'approveExecutionAndPayment',
1049
- gas: 50_000n,
1050
1089
  mode: 'verify',
1051
1090
  }),
1052
1091
  Frame.from({
1092
+ executionGas: 50_000n,
1053
1093
  flags: 'atomicBatch',
1054
- gas: 50_000n,
1055
1094
  mode: 'sender',
1056
1095
  to: accounts[1].address,
1057
1096
  value: 1n,
1058
1097
  }),
1059
1098
  Frame.from({
1099
+ executionGas: 50_000n,
1060
1100
  flags: 'atomicBatch',
1061
- gas: 50_000n,
1062
1101
  mode: 'sender',
1063
1102
  to: '0x0000000000000000000000000000000000001000',
1064
1103
  }),
1065
1104
  Frame.from({
1066
- gas: 50_000n,
1105
+ executionGas: 50_000n,
1067
1106
  mode: 'sender',
1068
1107
  to: accounts[1].address,
1069
1108
  value: 2n,
@@ -1131,8 +1170,8 @@ describe('serialize', () => {
1131
1170
  chainId: 8141,
1132
1171
  frames: [
1133
1172
  Frame.from({
1173
+ executionGas: 50_000n,
1134
1174
  flags: 'approveExecutionAndPayment',
1135
- gas: 50_000n,
1136
1175
  mode: 'verify',
1137
1176
  }),
1138
1177
  ],
@@ -1166,7 +1205,7 @@ describe('serialize', () => {
1166
1205
  ],
1167
1206
  }),
1168
1207
  ).rejects.toThrowErrorMatchingInlineSnapshot(
1169
- `[RpcResponse.InvalidInputError: transaction invalid, frame transaction SECP256K1 signer does not match the recovered address]`,
1208
+ `[RpcResponse.InvalidInputError: EIP-8141 public mempool policy: validation prefix execution failed]`,
1170
1209
  )
1171
1210
  })
1172
1211
 
@@ -1176,13 +1215,13 @@ describe('serialize', () => {
1176
1215
  frames: [
1177
1216
  Frame.from({
1178
1217
  data: '0x0000000000000001',
1179
- gas: 50_000n,
1218
+ executionGas: 20_000n,
1180
1219
  mode: 'verify',
1181
1220
  to: '0x0000000000000000000000000000000000008141',
1182
1221
  }),
1183
1222
  Frame.from({
1223
+ executionGas: 20_000n,
1184
1224
  flags: 'approveExecutionAndPayment',
1185
- gas: 50_000n,
1186
1225
  mode: 'verify',
1187
1226
  }),
1188
1227
  ],
@@ -1213,7 +1252,7 @@ describe('serialize', () => {
1213
1252
  params: [TxEnvelopeEip8141.serialize(signed)],
1214
1253
  }),
1215
1254
  ).rejects.toThrowErrorMatchingInlineSnapshot(
1216
- `[RpcResponse.InvalidInputError: frame transaction expired]`,
1255
+ `[RpcResponse.InvalidInputError: EIP-8141 public mempool policy: validation prefix execution failed]`,
1217
1256
  )
1218
1257
  })
1219
1258
 
@@ -1226,12 +1265,12 @@ describe('serialize', () => {
1226
1265
  chainId: 8141,
1227
1266
  frames: [
1228
1267
  Frame.from({
1268
+ executionGas: 50_000n,
1229
1269
  flags: 'approveExecutionAndPayment',
1230
- gas: 50_000n,
1231
1270
  mode: 'verify',
1232
1271
  }),
1233
1272
  Frame.from({
1234
- gas: 50_000n,
1273
+ executionGas: 50_000n,
1235
1274
  mode: 'sender',
1236
1275
  to: accounts[1].address,
1237
1276
  value: 1n,
@@ -1613,7 +1652,7 @@ describe('validate', () => {
1613
1652
  expect(
1614
1653
  TxEnvelopeEip8141.validate({
1615
1654
  chainId: 1,
1616
- frames: [{ gas: 2n ** 64n - 1n }, { stateGas: 1n }],
1655
+ frames: [{ executionGas: 2n ** 64n - 1n }, { stateGas: 1n }],
1617
1656
  sender: accounts[0].address,
1618
1657
  }),
1619
1658
  ).toBe(false)
@@ -1623,7 +1662,7 @@ describe('validate', () => {
1623
1662
  expect(
1624
1663
  TxEnvelopeEip8141.validate({
1625
1664
  chainId: 1,
1626
- frames: [{ gas: 16_777_216n }],
1665
+ frames: [{ executionGas: 16_777_216n }],
1627
1666
  sender: accounts[0].address,
1628
1667
  }),
1629
1668
  ).toBe(false)
@@ -1706,7 +1745,7 @@ describe('validate', () => {
1706
1745
 
1707
1746
  const frame = {
1708
1747
  data: '0x0000000000000001',
1709
- gas: 5000n,
1748
+ executionGas: 5000n,
1710
1749
  mode: 'verify',
1711
1750
  to: '0x0000000000000000000000000000000000008141',
1712
1751
  } as const
@@ -1738,10 +1777,10 @@ describe('toRpc', () => {
1738
1777
  frames: [
1739
1778
  {
1740
1779
  data: '0x',
1741
- executionGasLimit: '0x0',
1742
- flags: 0,
1743
- mode: 0,
1744
- stateGasLimit: '0x0',
1780
+ executionGas: '0x0',
1781
+ flags: '0x0',
1782
+ mode: '0x0',
1783
+ stateGas: '0x0',
1745
1784
  value: '0x0',
1746
1785
  },
1747
1786
  ],
@@ -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",
@@ -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.3'
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) => {
@@ -179,18 +179,18 @@ function eip8141Fields<
179
179
  data: z.optional(z_Hex.Hex),
180
180
  frames: z.readonly(z.array(frame)),
181
181
  from: z_Address.Address,
182
- gas: uint,
182
+ gas: z.optional(uint),
183
183
  gasPrice: z.optional(uint),
184
184
  hash: z_Hex.Hex,
185
- input: z_Hex.Hex,
185
+ input: z.optional(z_Hex.Hex),
186
186
  maxFeePerBlobGas: uint,
187
187
  maxFeePerGas: uint,
188
188
  maxPriorityFeePerGas: uint,
189
189
  nonce: uint,
190
190
  signatures: z.readonly(z.array(z_FrameSignature.FrameSignature)),
191
- to: z.nullable(z_Address.Address),
191
+ to: z.optional(z.nullable(z_Address.Address)),
192
192
  type: Eip8141Type,
193
- value: uint,
193
+ value: z.optional(uint),
194
194
  }
195
195
  }
196
196