ox 1.7.5 → 1.8.1
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.
- package/CHANGELOG.md +16 -0
- package/dist/core/Frame.d.ts +290 -0
- package/dist/core/Frame.d.ts.map +1 -0
- package/dist/core/Frame.js +306 -0
- package/dist/core/Frame.js.map +1 -0
- package/dist/core/FrameReceipt.d.ts +92 -0
- package/dist/core/FrameReceipt.d.ts.map +1 -0
- package/dist/core/FrameReceipt.js +72 -0
- package/dist/core/FrameReceipt.js.map +1 -0
- package/dist/core/FrameSignature.d.ts +357 -0
- package/dist/core/FrameSignature.d.ts.map +1 -0
- package/dist/core/FrameSignature.js +411 -0
- package/dist/core/FrameSignature.js.map +1 -0
- package/dist/core/Transaction.d.ts +29 -4
- package/dist/core/Transaction.d.ts.map +1 -1
- package/dist/core/Transaction.js +25 -4
- package/dist/core/Transaction.js.map +1 -1
- package/dist/core/TransactionReceipt.d.ts +13 -4
- package/dist/core/TransactionReceipt.d.ts.map +1 -1
- package/dist/core/TransactionReceipt.js +14 -0
- package/dist/core/TransactionReceipt.js.map +1 -1
- package/dist/core/TransactionRequest.d.ts +15 -7
- package/dist/core/TransactionRequest.d.ts.map +1 -1
- package/dist/core/TransactionRequest.js +47 -1
- package/dist/core/TransactionRequest.js.map +1 -1
- package/dist/core/TxEnvelope.d.ts +35 -21
- package/dist/core/TxEnvelope.d.ts.map +1 -1
- package/dist/core/TxEnvelope.js +46 -6
- package/dist/core/TxEnvelope.js.map +1 -1
- package/dist/core/TxEnvelopeEip8141.d.ts +341 -0
- package/dist/core/TxEnvelopeEip8141.d.ts.map +1 -0
- package/dist/core/TxEnvelopeEip8141.js +484 -0
- package/dist/core/TxEnvelopeEip8141.js.map +1 -0
- package/dist/core/internal/curves.d.ts +2 -0
- package/dist/core/internal/curves.d.ts.map +1 -1
- package/dist/core/internal/curves.js +2 -0
- package/dist/core/internal/curves.js.map +1 -1
- package/dist/index.d.ts +73 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -1
- package/dist/tempo/Transaction.d.ts +2 -0
- package/dist/tempo/Transaction.d.ts.map +1 -1
- package/dist/tempo/TransactionReceipt.d.ts +2 -0
- package/dist/tempo/TransactionReceipt.d.ts.map +1 -1
- package/dist/zod/Block.d.ts +123 -0
- package/dist/zod/Block.d.ts.map +1 -1
- package/dist/zod/Frame.d.ts +73 -0
- package/dist/zod/Frame.d.ts.map +1 -0
- package/dist/zod/Frame.js +74 -0
- package/dist/zod/Frame.js.map +1 -0
- package/dist/zod/FrameReceipt.d.ts +50 -0
- package/dist/zod/FrameReceipt.d.ts.map +1 -0
- package/dist/zod/FrameReceipt.js +37 -0
- package/dist/zod/FrameReceipt.js.map +1 -0
- package/dist/zod/FrameSignature.d.ts +63 -0
- package/dist/zod/FrameSignature.d.ts.map +1 -0
- package/dist/zod/FrameSignature.js +66 -0
- package/dist/zod/FrameSignature.js.map +1 -0
- package/dist/zod/RpcSchema.d.ts +806 -11
- package/dist/zod/RpcSchema.d.ts.map +1 -1
- package/dist/zod/Transaction.d.ts +252 -0
- package/dist/zod/Transaction.d.ts.map +1 -1
- package/dist/zod/Transaction.js +54 -0
- package/dist/zod/Transaction.js.map +1 -1
- package/dist/zod/TransactionEnvelope.d.ts +233 -4
- package/dist/zod/TransactionEnvelope.d.ts.map +1 -1
- package/dist/zod/TransactionEnvelope.js +9 -0
- package/dist/zod/TransactionEnvelope.js.map +1 -1
- package/dist/zod/TransactionReceipt.d.ts +48 -0
- package/dist/zod/TransactionReceipt.d.ts.map +1 -1
- package/dist/zod/TransactionReceipt.js +8 -3
- package/dist/zod/TransactionReceipt.js.map +1 -1
- package/dist/zod/TransactionRequest.d.ts +50 -2
- package/dist/zod/TransactionRequest.d.ts.map +1 -1
- package/dist/zod/TransactionRequest.js +10 -4
- package/dist/zod/TransactionRequest.js.map +1 -1
- package/dist/zod/TxEnvelopeEip8141.d.ts +166 -0
- package/dist/zod/TxEnvelopeEip8141.d.ts.map +1 -0
- package/dist/zod/TxEnvelopeEip8141.js +76 -0
- package/dist/zod/TxEnvelopeEip8141.js.map +1 -0
- package/dist/zod/internal/Frame.d.ts +4 -0
- package/dist/zod/internal/Frame.d.ts.map +1 -0
- package/dist/zod/internal/Frame.js +17 -0
- package/dist/zod/internal/Frame.js.map +1 -0
- package/dist/zod/internal/rpcSchemas/Eth.d.ts +842 -11
- package/dist/zod/internal/rpcSchemas/Eth.d.ts.map +1 -1
- package/dist/zod/internal/rpcSchemas/Wallet.d.ts +56 -2
- package/dist/zod/internal/rpcSchemas/Wallet.d.ts.map +1 -1
- package/dist/zod/tempo/RpcSchemaTempo.d.ts +140 -0
- package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/zod/tempo/Transaction.d.ts +123 -0
- package/dist/zod/tempo/Transaction.d.ts.map +1 -1
- package/dist/zod/z.d.ts +4 -0
- package/dist/zod/z.d.ts.map +1 -1
- package/dist/zod/z.js +4 -0
- package/dist/zod/z.js.map +1 -1
- package/package.json +41 -1
- package/src/core/Frame.ts +442 -0
- package/src/core/FrameReceipt.ts +117 -0
- package/src/core/FrameSignature.ts +593 -0
- package/src/core/Transaction.ts +82 -5
- package/src/core/TransactionReceipt.ts +41 -3
- package/src/core/TransactionRequest.ts +71 -4
- package/src/core/TxEnvelope.ts +159 -90
- package/src/core/TxEnvelopeEip8141.ts +714 -0
- package/src/core/_test/Frame.test-d.ts +108 -0
- package/src/core/_test/Frame.test.ts +280 -0
- package/src/core/_test/FrameReceipt.test.ts +86 -0
- package/src/core/_test/FrameSignature.test-d.ts +93 -0
- package/src/core/_test/FrameSignature.test.ts +554 -0
- package/src/core/_test/Transaction.test.ts +33 -0
- package/src/core/_test/TransactionEnvelope.test-d.ts +74 -0
- package/src/core/_test/TransactionEnvelope.test.ts +107 -0
- package/src/core/_test/TransactionReceipt.test.ts +59 -0
- package/src/core/_test/TransactionRequest.test-d.ts +50 -0
- package/src/core/_test/TransactionRequest.test.ts +88 -1
- package/src/core/_test/TxEnvelopeEip8141.test-d.ts +44 -0
- package/src/core/_test/TxEnvelopeEip8141.test.ts +1775 -0
- package/src/core/_test/curves.test.ts +6 -1
- package/src/core/_test/index.test.ts +4 -0
- package/src/core/internal/curves.ts +4 -0
- package/src/index.ts +77 -0
- package/src/version.ts +1 -1
- package/src/zod/Frame.ts +82 -0
- package/src/zod/FrameReceipt.ts +48 -0
- package/src/zod/FrameSignature.ts +78 -0
- package/src/zod/Transaction.ts +63 -0
- package/src/zod/TransactionEnvelope.ts +33 -0
- package/src/zod/TransactionReceipt.ts +14 -3
- package/src/zod/TransactionRequest.ts +18 -3
- package/src/zod/TxEnvelopeEip8141.ts +102 -0
- package/src/zod/_test/Frame.test-d.ts +41 -0
- package/src/zod/_test/Frame.test.ts +57 -0
- package/src/zod/_test/FrameReceipt.test.ts +75 -0
- package/src/zod/_test/FrameSignature.test.ts +94 -0
- package/src/zod/_test/TxEnvelopeEip8141.test.ts +116 -0
- package/src/zod/internal/Frame.ts +26 -0
- package/src/zod/z.ts +4 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Frame,
|
|
3
|
+
FrameSignature,
|
|
2
4
|
TransactionEnvelope,
|
|
3
5
|
TxEnvelopeEip1559,
|
|
4
6
|
TxEnvelopeEip2930,
|
|
5
7
|
TxEnvelopeEip4844,
|
|
6
8
|
TxEnvelopeEip7702,
|
|
9
|
+
TxEnvelopeEip8141,
|
|
7
10
|
TxEnvelopeLegacy,
|
|
8
11
|
} from 'ox'
|
|
9
12
|
import { describe, expect, test } from 'vp/test'
|
|
@@ -62,6 +65,14 @@ const eip7702 = TxEnvelopeEip7702.from({
|
|
|
62
65
|
value: 1n,
|
|
63
66
|
})
|
|
64
67
|
|
|
68
|
+
const eip8141 = TxEnvelopeEip8141.from({
|
|
69
|
+
chainId: 1,
|
|
70
|
+
frames: [Frame.from({})],
|
|
71
|
+
sender: '0x1111111111111111111111111111111111111111',
|
|
72
|
+
})
|
|
73
|
+
const serialized8141 =
|
|
74
|
+
'0x06e70180941111111111111111111111111111111111111111c9c8808080c280808080c0c3808080c0'
|
|
75
|
+
|
|
65
76
|
test('exports', () => {
|
|
66
77
|
expect(Object.keys(TransactionEnvelope)).toMatchInlineSnapshot(`
|
|
67
78
|
[
|
|
@@ -88,6 +99,25 @@ test('exports', () => {
|
|
|
88
99
|
})
|
|
89
100
|
|
|
90
101
|
describe('getType', () => {
|
|
102
|
+
test('frame fields take precedence over blobs and fees', () => {
|
|
103
|
+
expect(
|
|
104
|
+
TransactionEnvelope.getType({
|
|
105
|
+
blobVersionedHashes: [],
|
|
106
|
+
frames: [],
|
|
107
|
+
maxFeePerGas: 1n,
|
|
108
|
+
}),
|
|
109
|
+
).toBe('eip8141')
|
|
110
|
+
expect(
|
|
111
|
+
TransactionEnvelope.getType({ frames: undefined, maxFeePerGas: 1n }),
|
|
112
|
+
).toBe('eip1559')
|
|
113
|
+
expect(TransactionEnvelope.getType({ frames: [], type: 'eip1559' })).toBe(
|
|
114
|
+
'eip1559',
|
|
115
|
+
)
|
|
116
|
+
expect(() => TransactionEnvelope.getType({ type: '0x6' })).toThrow(
|
|
117
|
+
TransactionEnvelope.InvalidTypeError,
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
|
|
91
121
|
test('behavior: routes explicit transaction types', () => {
|
|
92
122
|
expect(TransactionEnvelope.getType(legacy)).toBe('legacy')
|
|
93
123
|
expect(TransactionEnvelope.getType(eip2930)).toBe('eip2930')
|
|
@@ -156,6 +186,12 @@ describe('getType', () => {
|
|
|
156
186
|
})
|
|
157
187
|
|
|
158
188
|
describe('getSerializedType', () => {
|
|
189
|
+
test('eip8141', () => {
|
|
190
|
+
expect(TransactionEnvelope.getSerializedType(serialized8141)).toBe(
|
|
191
|
+
'eip8141',
|
|
192
|
+
)
|
|
193
|
+
})
|
|
194
|
+
|
|
159
195
|
test('behavior: routes serialized transaction types', () => {
|
|
160
196
|
expect(
|
|
161
197
|
TransactionEnvelope.getSerializedType(TxEnvelopeLegacy.serialize(legacy)),
|
|
@@ -202,6 +238,12 @@ describe('getSerializedType', () => {
|
|
|
202
238
|
})
|
|
203
239
|
|
|
204
240
|
describe('deserialize', () => {
|
|
241
|
+
test('eip8141', () => {
|
|
242
|
+
expect(TransactionEnvelope.deserialize(serialized8141)).toEqual(
|
|
243
|
+
TxEnvelopeEip8141.deserialize(serialized8141),
|
|
244
|
+
)
|
|
245
|
+
})
|
|
246
|
+
|
|
205
247
|
test('behavior: routes to the matching concrete deserializer', () => {
|
|
206
248
|
const serialized = TxEnvelopeEip1559.serialize(eip1559)
|
|
207
249
|
|
|
@@ -212,6 +254,14 @@ describe('deserialize', () => {
|
|
|
212
254
|
})
|
|
213
255
|
|
|
214
256
|
describe('from', () => {
|
|
257
|
+
test('eip8141', () => {
|
|
258
|
+
const { type: _, ...input } = eip8141
|
|
259
|
+
expect(TransactionEnvelope.from(input)).toEqual(eip8141)
|
|
260
|
+
expect(TransactionEnvelope.from(serialized8141)).toEqual(
|
|
261
|
+
TxEnvelopeEip8141.deserialize(serialized8141),
|
|
262
|
+
)
|
|
263
|
+
})
|
|
264
|
+
|
|
215
265
|
test('behavior: routes objects to the matching concrete converter', () => {
|
|
216
266
|
expect(TransactionEnvelope.from({ maxFeePerGas: 10n, chainId: 1 })).toEqual(
|
|
217
267
|
TxEnvelopeEip1559.from({ maxFeePerGas: 10n, chainId: 1 }),
|
|
@@ -244,6 +294,26 @@ describe('from', () => {
|
|
|
244
294
|
})
|
|
245
295
|
|
|
246
296
|
describe('getSignPayload', () => {
|
|
297
|
+
test('eip8141 signature elision', () => {
|
|
298
|
+
const envelope = TxEnvelopeEip8141.from({
|
|
299
|
+
...eip8141,
|
|
300
|
+
signatures: [
|
|
301
|
+
FrameSignature.from('0xaabb'),
|
|
302
|
+
FrameSignature.from({
|
|
303
|
+
payload: `0x${'ab'.repeat(32)}`,
|
|
304
|
+
signature: '0xccdd',
|
|
305
|
+
}),
|
|
306
|
+
],
|
|
307
|
+
})
|
|
308
|
+
expect(TransactionEnvelope.getSignPayload(envelope)).toBe(
|
|
309
|
+
'0x85ec4544ddb227c5425add4b606f71ddfc0852100d14066d0061a1b092bad6d3',
|
|
310
|
+
)
|
|
311
|
+
expect(TransactionEnvelope.hash(envelope, { presign: true })).toBe(
|
|
312
|
+
TransactionEnvelope.getSignPayload(envelope),
|
|
313
|
+
)
|
|
314
|
+
expect(envelope.signatures[0].signature).toBe('0xaabb')
|
|
315
|
+
})
|
|
316
|
+
|
|
247
317
|
test('behavior: routes to the matching concrete payload helper', () => {
|
|
248
318
|
expect(TransactionEnvelope.getSignPayload(eip1559)).toBe(
|
|
249
319
|
TxEnvelopeEip1559.getSignPayload(eip1559),
|
|
@@ -252,6 +322,12 @@ describe('getSignPayload', () => {
|
|
|
252
322
|
})
|
|
253
323
|
|
|
254
324
|
describe('hash', () => {
|
|
325
|
+
test('eip8141 without outer signature fields', () => {
|
|
326
|
+
expect(TransactionEnvelope.hash(eip8141)).toBe(
|
|
327
|
+
'0xa795b6de44696d46c096aaa3d6401d6eaa21b9b639408c82be7e9e60358e4387',
|
|
328
|
+
)
|
|
329
|
+
})
|
|
330
|
+
|
|
255
331
|
test('behavior: routes to the matching concrete hash helper', () => {
|
|
256
332
|
expect(TransactionEnvelope.hash(eip1559, { presign: true })).toBe(
|
|
257
333
|
TxEnvelopeEip1559.hash(eip1559, { presign: true }),
|
|
@@ -260,6 +336,10 @@ describe('hash', () => {
|
|
|
260
336
|
})
|
|
261
337
|
|
|
262
338
|
describe('serialize', () => {
|
|
339
|
+
test('eip8141', () => {
|
|
340
|
+
expect(TransactionEnvelope.serialize(eip8141)).toBe(serialized8141)
|
|
341
|
+
})
|
|
342
|
+
|
|
263
343
|
test('behavior: routes to the matching concrete serializer', () => {
|
|
264
344
|
expect(TransactionEnvelope.serialize(eip1559)).toBe(
|
|
265
345
|
TxEnvelopeEip1559.serialize(eip1559),
|
|
@@ -284,6 +364,12 @@ describe('serialize', () => {
|
|
|
284
364
|
})
|
|
285
365
|
|
|
286
366
|
describe('toRpc', () => {
|
|
367
|
+
test('converts frame envelopes', () => {
|
|
368
|
+
expect(TransactionEnvelope.toRpc(eip8141)).toEqual(
|
|
369
|
+
TxEnvelopeEip8141.toRpc(eip8141),
|
|
370
|
+
)
|
|
371
|
+
})
|
|
372
|
+
|
|
287
373
|
test('behavior: routes to the matching concrete RPC converter', () => {
|
|
288
374
|
expect(TransactionEnvelope.toRpc(eip1559)).toEqual(
|
|
289
375
|
TxEnvelopeEip1559.toRpc(eip1559),
|
|
@@ -292,6 +378,13 @@ describe('toRpc', () => {
|
|
|
292
378
|
})
|
|
293
379
|
|
|
294
380
|
describe('assert', () => {
|
|
381
|
+
test('eip8141', () => {
|
|
382
|
+
expect(() => TransactionEnvelope.assert(eip8141)).not.toThrow()
|
|
383
|
+
expect(() =>
|
|
384
|
+
TransactionEnvelope.assert({ ...eip8141, frames: [] }),
|
|
385
|
+
).toThrow(TxEnvelopeEip8141.InvalidError)
|
|
386
|
+
})
|
|
387
|
+
|
|
295
388
|
test('behavior: routes to the matching concrete assertion', () => {
|
|
296
389
|
expect(() =>
|
|
297
390
|
TransactionEnvelope.assert({
|
|
@@ -306,6 +399,11 @@ describe('assert', () => {
|
|
|
306
399
|
})
|
|
307
400
|
|
|
308
401
|
describe('validate', () => {
|
|
402
|
+
test('eip8141', () => {
|
|
403
|
+
expect(TransactionEnvelope.validate(eip8141)).toBe(true)
|
|
404
|
+
expect(TransactionEnvelope.validate({ ...eip8141, frames: [] })).toBe(false)
|
|
405
|
+
})
|
|
406
|
+
|
|
309
407
|
test('behavior: returns validation result for routed envelope', () => {
|
|
310
408
|
expect(TransactionEnvelope.validate(eip1559)).toBe(true)
|
|
311
409
|
expect(
|
|
@@ -333,6 +431,15 @@ describe('getType', () => {
|
|
|
333
431
|
})
|
|
334
432
|
|
|
335
433
|
describe('toTransactionRequest', () => {
|
|
434
|
+
test('maps frame sender to request from', () => {
|
|
435
|
+
expect(TransactionEnvelope.toTransactionRequest(eip8141)).toEqual({
|
|
436
|
+
chainId: 1,
|
|
437
|
+
frames: [{}],
|
|
438
|
+
from: '0x1111111111111111111111111111111111111111',
|
|
439
|
+
type: 'eip8141',
|
|
440
|
+
})
|
|
441
|
+
})
|
|
442
|
+
|
|
336
443
|
test('behavior: eip1559', () => {
|
|
337
444
|
const request = TransactionEnvelope.toTransactionRequest(eip1559)
|
|
338
445
|
expect(request).toMatchInlineSnapshot(`
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TransactionReceipt } from 'ox'
|
|
2
|
+
import { z } from 'ox/zod'
|
|
2
3
|
import { describe, expect, test } from 'vp/test'
|
|
3
4
|
import { anvilMainnet } from '../../../test/prool.js'
|
|
4
5
|
|
|
@@ -457,3 +458,61 @@ test('exports', () => {
|
|
|
457
458
|
]
|
|
458
459
|
`)
|
|
459
460
|
})
|
|
461
|
+
|
|
462
|
+
describe('frame receipts', () => {
|
|
463
|
+
test('preserves payer, statuses, logs, and large gas totals', () => {
|
|
464
|
+
const rpc = {
|
|
465
|
+
blockHash: '0x00',
|
|
466
|
+
blockNumber: '0x1',
|
|
467
|
+
cumulativeGasUsed: '0x20000000000001',
|
|
468
|
+
effectiveGasPrice: '0x1',
|
|
469
|
+
frameReceipts: [
|
|
470
|
+
{
|
|
471
|
+
executionGasUsed: '0x20000000000001',
|
|
472
|
+
logs: [
|
|
473
|
+
{
|
|
474
|
+
address: '0x1111111111111111111111111111111111111111',
|
|
475
|
+
data: '0xab',
|
|
476
|
+
topics: ['0x01'],
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
stateGasUsed: '0x2',
|
|
480
|
+
status: 1,
|
|
481
|
+
},
|
|
482
|
+
{ executionGasUsed: '0x3', logs: [], stateGasUsed: '0x0', status: 0 },
|
|
483
|
+
{ executionGasUsed: '0x0', logs: [], stateGasUsed: '0x0', status: 2 },
|
|
484
|
+
],
|
|
485
|
+
from: '0x1111111111111111111111111111111111111111',
|
|
486
|
+
gasUsed: '0x20000000000001',
|
|
487
|
+
logs: [],
|
|
488
|
+
logsBloom: '0x00',
|
|
489
|
+
payer: '0x2222222222222222222222222222222222222222',
|
|
490
|
+
status: '0x0',
|
|
491
|
+
to: null,
|
|
492
|
+
transactionHash: '0x00',
|
|
493
|
+
transactionIndex: '0x0',
|
|
494
|
+
type: '0x6',
|
|
495
|
+
} satisfies TransactionReceipt.Rpc
|
|
496
|
+
const receipt = TransactionReceipt.fromRpc(rpc)
|
|
497
|
+
expect(receipt.type).toBe('eip8141')
|
|
498
|
+
expect(receipt.payer).toBe(rpc.payer)
|
|
499
|
+
expect(receipt.frameReceipts).toEqual([
|
|
500
|
+
{
|
|
501
|
+
gasUsed: 9007199254740993n,
|
|
502
|
+
logs: rpc.frameReceipts[0]!.logs,
|
|
503
|
+
stateGasUsed: 2n,
|
|
504
|
+
status: 'success',
|
|
505
|
+
},
|
|
506
|
+
{ gasUsed: 3n, logs: [], stateGasUsed: 0n, status: 'reverted' },
|
|
507
|
+
{ gasUsed: 0n, logs: [], stateGasUsed: 0n, status: 'skipped' },
|
|
508
|
+
])
|
|
509
|
+
expect(TransactionReceipt.toRpc(receipt)).toMatchObject(rpc)
|
|
510
|
+
expect(
|
|
511
|
+
z.decode(z.TransactionReceipt.TransactionReceipt, rpc).frameReceipts,
|
|
512
|
+
).toEqual(receipt.frameReceipts)
|
|
513
|
+
expect(
|
|
514
|
+
z.encode(z.TransactionReceipt.TransactionReceipt, receipt).frameReceipts,
|
|
515
|
+
).toEqual(rpc.frameReceipts)
|
|
516
|
+
expect(rpc.frameReceipts[0]!.executionGasUsed).toBe('0x20000000000001')
|
|
517
|
+
})
|
|
518
|
+
})
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type Frame,
|
|
3
|
+
type FrameSignature,
|
|
2
4
|
TransactionEnvelope,
|
|
3
5
|
type TransactionRequest as TransactionRequestNs,
|
|
4
6
|
TransactionRequest,
|
|
@@ -117,9 +119,57 @@ describe('round-trip: Request → Envelope → Request', () => {
|
|
|
117
119
|
value: 1n,
|
|
118
120
|
}
|
|
119
121
|
const envelope = TransactionRequest.toEnvelope(request)
|
|
122
|
+
if ('frames' in envelope) throw new Error('Expected a non-frame envelope')
|
|
120
123
|
const roundtripped = TransactionEnvelope.toTransactionRequest(envelope)
|
|
121
124
|
expectTypeOf(
|
|
122
125
|
roundtripped,
|
|
123
126
|
).toEqualTypeOf<TransactionRequestNs.TransactionRequest>()
|
|
124
127
|
})
|
|
125
128
|
})
|
|
129
|
+
|
|
130
|
+
describe('frame generics', () => {
|
|
131
|
+
test('decoded defaults', () => {
|
|
132
|
+
expectTypeOf<
|
|
133
|
+
TransactionRequest.TransactionRequest['frames']
|
|
134
|
+
>().toEqualTypeOf<readonly Frame.Frame[] | undefined>()
|
|
135
|
+
expectTypeOf<
|
|
136
|
+
TransactionRequest.TransactionRequest['signatures']
|
|
137
|
+
>().toEqualTypeOf<readonly FrameSignature.FrameSignature[] | undefined>()
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('RPC types', () => {
|
|
141
|
+
expectTypeOf<TransactionRequest.Rpc['frames']>().toEqualTypeOf<
|
|
142
|
+
readonly Frame.Rpc[] | undefined
|
|
143
|
+
>()
|
|
144
|
+
expectTypeOf<TransactionRequest.Rpc['signatures']>().toEqualTypeOf<
|
|
145
|
+
readonly FrameSignature.Rpc[] | undefined
|
|
146
|
+
>()
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('custom frame and signature types', () => {
|
|
150
|
+
type Request = TransactionRequest.TransactionRequest<
|
|
151
|
+
bigint,
|
|
152
|
+
number,
|
|
153
|
+
string,
|
|
154
|
+
Frame.Frame & { label: string },
|
|
155
|
+
FrameSignature.Arbitrary
|
|
156
|
+
>
|
|
157
|
+
expectTypeOf<Request['frames']>().toEqualTypeOf<
|
|
158
|
+
readonly (Frame.Frame & { label: string })[] | undefined
|
|
159
|
+
>()
|
|
160
|
+
expectTypeOf<Request['signatures']>().toEqualTypeOf<
|
|
161
|
+
readonly FrameSignature.Arbitrary[] | undefined
|
|
162
|
+
>()
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('chain ID remains a number for every request type', () => {
|
|
167
|
+
expectTypeOf<
|
|
168
|
+
TransactionRequest.TransactionRequest['chainId']
|
|
169
|
+
>().toEqualTypeOf<number | undefined>()
|
|
170
|
+
expectTypeOf<
|
|
171
|
+
TransactionRequest.TransactionRequest<bigint, number, 'eip8141'>['chainId']
|
|
172
|
+
>().toEqualTypeOf<number | undefined>()
|
|
173
|
+
// @ts-expect-error Request chain IDs must be numbers.
|
|
174
|
+
TransactionRequest.toEnvelope({ chainId: 1n, type: 'eip1559' })
|
|
175
|
+
})
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Blobs,
|
|
3
|
+
Frame,
|
|
4
|
+
FrameSignature,
|
|
5
|
+
Hex,
|
|
6
|
+
TransactionEnvelope,
|
|
7
|
+
TransactionRequest,
|
|
8
|
+
TxEnvelopeEip8141,
|
|
9
|
+
Value,
|
|
10
|
+
} from 'ox'
|
|
2
11
|
import { describe, expect, test } from 'vp/test'
|
|
3
12
|
import { kzg } from '../../../test/kzg.js'
|
|
4
13
|
import { anvilMainnet } from '../../../test/prool.js'
|
|
@@ -428,3 +437,81 @@ test('exports', () => {
|
|
|
428
437
|
]
|
|
429
438
|
`)
|
|
430
439
|
})
|
|
440
|
+
|
|
441
|
+
describe('frame transactions', () => {
|
|
442
|
+
test('derives frame blob sidecars and replaces stale hashes', () => {
|
|
443
|
+
const blobs = Blobs.from('0xdeadbeef')
|
|
444
|
+
const request = {
|
|
445
|
+
blobVersionedHashes: [],
|
|
446
|
+
blobs,
|
|
447
|
+
chainId: 1,
|
|
448
|
+
frames: [Frame.from({})],
|
|
449
|
+
from: '0x1111111111111111111111111111111111111111' as const,
|
|
450
|
+
maxFeePerBlobGas: 1n,
|
|
451
|
+
}
|
|
452
|
+
expect(() => TransactionRequest.toEnvelope(request)).toThrow(
|
|
453
|
+
TransactionRequest.MissingKzgError,
|
|
454
|
+
)
|
|
455
|
+
const envelope = TransactionRequest.toEnvelope(request, { kzg })
|
|
456
|
+
expect(envelope.type).toBe('eip8141')
|
|
457
|
+
if (envelope.type !== 'eip8141') throw new Error('Expected frame envelope')
|
|
458
|
+
expect(envelope.sidecars?.blobs).toEqual(blobs)
|
|
459
|
+
expect(envelope.sidecars?.cellProofs).toHaveLength(128)
|
|
460
|
+
expect(
|
|
461
|
+
TxEnvelopeEip8141.deserialize(TxEnvelopeEip8141.serialize(envelope))
|
|
462
|
+
.blobVersionedHashes,
|
|
463
|
+
).toEqual(envelope.blobVersionedHashes)
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
test('round-trips frame requests and envelopes', () => {
|
|
467
|
+
const envelope = TxEnvelopeEip8141.from({
|
|
468
|
+
chainId: 8141,
|
|
469
|
+
frames: [Frame.from({ gas: 50_000n, mode: 'verify' })],
|
|
470
|
+
sender: '0x1111111111111111111111111111111111111111',
|
|
471
|
+
signatures: [FrameSignature.from('0xaabb')],
|
|
472
|
+
})
|
|
473
|
+
const request = TransactionEnvelope.toTransactionRequest(envelope)
|
|
474
|
+
const rpc = TransactionRequest.toRpc(request)
|
|
475
|
+
expect(rpc.chainId).toBe('0x1fcd')
|
|
476
|
+
expect(rpc.type).toBe('0x6')
|
|
477
|
+
expect(rpc.signatures).toEqual([
|
|
478
|
+
{ msg: '0x', scheme: 0, signature: '0xaabb' },
|
|
479
|
+
])
|
|
480
|
+
const decoded = TransactionRequest.fromRpc(rpc)
|
|
481
|
+
expect(decoded.chainId).toBe(8141)
|
|
482
|
+
expect(
|
|
483
|
+
TxEnvelopeEip8141.serialize(
|
|
484
|
+
TransactionRequest.toEnvelope(
|
|
485
|
+
decoded,
|
|
486
|
+
) as TxEnvelopeEip8141.TxEnvelopeEip8141,
|
|
487
|
+
),
|
|
488
|
+
).toBe(TxEnvelopeEip8141.serialize(envelope))
|
|
489
|
+
})
|
|
490
|
+
test('requires a sender', () => {
|
|
491
|
+
expect(() =>
|
|
492
|
+
TransactionRequest.toEnvelope({ chainId: 1, frames: [] }),
|
|
493
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
494
|
+
`[Quantity.MissingFieldError: Missing required field \`from\` on \`TransactionRequest\`.]`,
|
|
495
|
+
)
|
|
496
|
+
})
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
describe('chain ID precision', () => {
|
|
500
|
+
test('rejects unsafe RPC chain IDs', () => {
|
|
501
|
+
expect(() =>
|
|
502
|
+
TransactionRequest.fromRpc({
|
|
503
|
+
chainId: '0x20000000000001',
|
|
504
|
+
frames: [],
|
|
505
|
+
type: '0x6',
|
|
506
|
+
}),
|
|
507
|
+
).toThrow()
|
|
508
|
+
})
|
|
509
|
+
test('rejects unsafe envelope chain IDs when converting to a request', () => {
|
|
510
|
+
const envelope = TxEnvelopeEip8141.from({
|
|
511
|
+
chainId: 9007199254740993n,
|
|
512
|
+
frames: [Frame.from({})],
|
|
513
|
+
sender: '0x1111111111111111111111111111111111111111',
|
|
514
|
+
})
|
|
515
|
+
expect(() => TransactionEnvelope.toTransactionRequest(envelope)).toThrow()
|
|
516
|
+
})
|
|
517
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { TxEnvelopeEip8141 } from 'ox'
|
|
2
|
+
import { expectTypeOf, test } from 'vp/test'
|
|
3
|
+
|
|
4
|
+
test('default', () => {
|
|
5
|
+
const envelope = TxEnvelopeEip8141.from({
|
|
6
|
+
chainId: 1,
|
|
7
|
+
frames: [{ gas: 50000n }],
|
|
8
|
+
sender: '0x1111111111111111111111111111111111111111',
|
|
9
|
+
})
|
|
10
|
+
expectTypeOf(envelope).toEqualTypeOf<{
|
|
11
|
+
readonly chainId: 1
|
|
12
|
+
readonly frames: readonly [{ readonly gas: 50000n }]
|
|
13
|
+
readonly sender: '0x1111111111111111111111111111111111111111'
|
|
14
|
+
readonly type: 'eip8141'
|
|
15
|
+
}>()
|
|
16
|
+
expectTypeOf(envelope).toMatchTypeOf<TxEnvelopeEip8141.TxEnvelopeEip8141>()
|
|
17
|
+
expectTypeOf(
|
|
18
|
+
TxEnvelopeEip8141.serialize(envelope),
|
|
19
|
+
).toEqualTypeOf<TxEnvelopeEip8141.Serialized>()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('serialized', () => {
|
|
23
|
+
const envelope = TxEnvelopeEip8141.from(
|
|
24
|
+
'0x06' as TxEnvelopeEip8141.Serialized,
|
|
25
|
+
)
|
|
26
|
+
expectTypeOf(envelope).toEqualTypeOf<TxEnvelopeEip8141.TxEnvelopeEip8141>()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('unsigned signature', () => {
|
|
30
|
+
const envelope = TxEnvelopeEip8141.from({
|
|
31
|
+
chainId: 1n,
|
|
32
|
+
frames: [{}],
|
|
33
|
+
sender: '0x1111111111111111111111111111111111111111',
|
|
34
|
+
signatures: [{ scheme: 'secp256k1' }],
|
|
35
|
+
})
|
|
36
|
+
expectTypeOf(envelope).toEqualTypeOf<{
|
|
37
|
+
readonly chainId: 1n
|
|
38
|
+
readonly frames: readonly [{}]
|
|
39
|
+
readonly sender: '0x1111111111111111111111111111111111111111'
|
|
40
|
+
readonly signatures: readonly [{ readonly scheme: 'secp256k1' }]
|
|
41
|
+
readonly type: 'eip8141'
|
|
42
|
+
}>()
|
|
43
|
+
expectTypeOf(envelope).toMatchTypeOf<TxEnvelopeEip8141.TxEnvelopeEip8141>()
|
|
44
|
+
})
|