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.
- package/CHANGELOG.md +53 -0
- package/dist/core/Frame.d.ts +23 -20
- package/dist/core/Frame.d.ts.map +1 -1
- package/dist/core/Frame.js +28 -23
- package/dist/core/Frame.js.map +1 -1
- package/dist/core/FrameReceipt.d.ts +23 -14
- package/dist/core/FrameReceipt.d.ts.map +1 -1
- package/dist/core/FrameReceipt.js +15 -11
- package/dist/core/FrameReceipt.js.map +1 -1
- package/dist/core/FrameRequest.d.ts +50 -0
- package/dist/core/FrameRequest.d.ts.map +1 -0
- package/dist/core/FrameRequest.js +59 -0
- package/dist/core/FrameRequest.js.map +1 -0
- package/dist/core/FrameSignature.d.ts +17 -16
- package/dist/core/FrameSignature.d.ts.map +1 -1
- package/dist/core/FrameSignature.js +38 -21
- package/dist/core/FrameSignature.js.map +1 -1
- package/dist/core/Siwe.d.ts.map +1 -1
- package/dist/core/Siwe.js +3 -3
- package/dist/core/Siwe.js.map +1 -1
- package/dist/core/Transaction.d.ts +7 -4
- package/dist/core/Transaction.d.ts.map +1 -1
- package/dist/core/Transaction.js +8 -0
- package/dist/core/Transaction.js.map +1 -1
- package/dist/core/TransactionRequest.d.ts +8 -5
- package/dist/core/TransactionRequest.d.ts.map +1 -1
- package/dist/core/TransactionRequest.js +11 -3
- package/dist/core/TransactionRequest.js.map +1 -1
- package/dist/core/TxEnvelope.d.ts +4 -2
- package/dist/core/TxEnvelope.d.ts.map +1 -1
- package/dist/core/TxEnvelope.js +11 -2
- package/dist/core/TxEnvelope.js.map +1 -1
- package/dist/core/TxEnvelopeEip8141.d.ts +22 -11
- package/dist/core/TxEnvelopeEip8141.d.ts.map +1 -1
- package/dist/core/TxEnvelopeEip8141.js +45 -16
- package/dist/core/TxEnvelopeEip8141.js.map +1 -1
- package/dist/core/internal/frameNonce.d.ts +10 -0
- package/dist/core/internal/frameNonce.d.ts.map +1 -0
- package/dist/core/internal/frameNonce.js +45 -0
- package/dist/core/internal/frameNonce.js.map +1 -0
- package/dist/core/internal/rpcSchemas/eth.d.ts +16 -4
- package/dist/core/internal/rpcSchemas/eth.d.ts.map +1 -1
- package/dist/index.d.ts +21 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -5
- package/dist/index.js.map +1 -1
- package/dist/zod/Block.d.ts +52 -37
- package/dist/zod/Block.d.ts.map +1 -1
- package/dist/zod/Frame.d.ts +14 -14
- package/dist/zod/Frame.js +5 -5
- package/dist/zod/Frame.js.map +1 -1
- package/dist/zod/FrameReceipt.d.ts +42 -2
- package/dist/zod/FrameReceipt.d.ts.map +1 -1
- package/dist/zod/FrameReceipt.js +11 -1
- package/dist/zod/FrameReceipt.js.map +1 -1
- package/dist/zod/FrameRequest.d.ts +40 -0
- package/dist/zod/FrameRequest.d.ts.map +1 -0
- package/dist/zod/FrameRequest.js +37 -0
- package/dist/zod/FrameRequest.js.map +1 -0
- package/dist/zod/FrameSignature.d.ts +21 -13
- package/dist/zod/FrameSignature.d.ts.map +1 -1
- package/dist/zod/FrameSignature.js +10 -7
- package/dist/zod/FrameSignature.js.map +1 -1
- package/dist/zod/RpcSchema.d.ts +470 -265
- package/dist/zod/RpcSchema.d.ts.map +1 -1
- package/dist/zod/Transaction.d.ts +104 -74
- package/dist/zod/Transaction.d.ts.map +1 -1
- package/dist/zod/Transaction.js +22 -15
- package/dist/zod/Transaction.js.map +1 -1
- package/dist/zod/TransactionEnvelope.d.ts +60 -34
- package/dist/zod/TransactionEnvelope.d.ts.map +1 -1
- package/dist/zod/TransactionReceipt.d.ts +42 -2
- package/dist/zod/TransactionReceipt.d.ts.map +1 -1
- package/dist/zod/TransactionRequest.d.ts +31 -21
- 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 +44 -25
- package/dist/zod/TxEnvelopeEip8141.d.ts.map +1 -1
- package/dist/zod/TxEnvelopeEip8141.js +2 -0
- package/dist/zod/TxEnvelopeEip8141.js.map +1 -1
- package/dist/zod/internal/Frame.d.ts +8 -0
- package/dist/zod/internal/Frame.d.ts.map +1 -1
- package/dist/zod/internal/Frame.js +29 -0
- package/dist/zod/internal/Frame.js.map +1 -1
- package/dist/zod/internal/rpcSchemas/Eth.d.ts +472 -267
- package/dist/zod/internal/rpcSchemas/Eth.d.ts.map +1 -1
- package/dist/zod/internal/rpcSchemas/Eth.js +9 -0
- package/dist/zod/internal/rpcSchemas/Eth.js.map +1 -1
- package/dist/zod/internal/rpcSchemas/Wallet.d.ts +51 -21
- package/dist/zod/internal/rpcSchemas/Wallet.d.ts.map +1 -1
- package/dist/zod/tempo/RpcSchemaTempo.d.ts +68 -48
- package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/zod/tempo/Transaction.d.ts +52 -37
- package/dist/zod/tempo/Transaction.d.ts.map +1 -1
- package/dist/zod/z.d.ts +1 -0
- package/dist/zod/z.d.ts.map +1 -1
- package/dist/zod/z.js +1 -0
- package/dist/zod/z.js.map +1 -1
- package/package.json +11 -1
- package/src/core/Frame.ts +41 -33
- package/src/core/FrameReceipt.ts +30 -16
- package/src/core/FrameRequest.ts +78 -0
- package/src/core/FrameSignature.ts +64 -34
- package/src/core/Siwe.ts +21 -13
- package/src/core/Transaction.ts +52 -24
- package/src/core/TransactionRequest.ts +21 -7
- package/src/core/TxEnvelope.ts +16 -3
- package/src/core/TxEnvelopeEip8141.ts +69 -21
- package/src/core/_test/AbiConstructor.test.ts +2 -0
- package/src/core/_test/Frame.test-d.ts +16 -7
- package/src/core/_test/Frame.test.ts +52 -24
- package/src/core/_test/FrameReceipt.test.ts +15 -9
- package/src/core/_test/FrameRequest.test-d.ts +16 -0
- package/src/core/_test/FrameRequest.test.ts +41 -0
- package/src/core/_test/FrameRpc.test.ts +131 -0
- package/src/core/_test/FrameSignature.test-d.ts +20 -0
- package/src/core/_test/FrameSignature.test.ts +132 -11
- package/src/core/_test/RpcSchema.test-d.ts +45 -0
- package/src/core/_test/Siwe.test.ts +147 -0
- package/src/core/_test/TransactionEnvelope.test-d.ts +27 -0
- package/src/core/_test/TransactionEnvelope.test.ts +27 -1
- package/src/core/_test/TransactionReceipt.test.ts +32 -6
- package/src/core/_test/TransactionRequest.test-d.ts +10 -1
- package/src/core/_test/TransactionRequest.test.ts +31 -2
- package/src/core/_test/TxEnvelopeEip8141.test-d.ts +29 -2
- package/src/core/_test/TxEnvelopeEip8141.test.ts +548 -55
- package/src/core/_test/index.test.ts +1 -0
- package/src/core/internal/frameNonce.ts +61 -0
- package/src/core/internal/rpcSchemas/eth.ts +13 -4
- package/src/index.ts +22 -5
- package/src/version.ts +1 -1
- package/src/zod/Frame.ts +5 -5
- package/src/zod/FrameReceipt.ts +11 -1
- package/src/zod/FrameRequest.ts +46 -0
- package/src/zod/FrameSignature.ts +10 -7
- package/src/zod/Transaction.ts +46 -27
- package/src/zod/TransactionRequest.ts +33 -18
- package/src/zod/TxEnvelopeEip8141.ts +2 -0
- package/src/zod/_test/Frame.test.ts +13 -11
- package/src/zod/_test/FrameReceipt.test.ts +11 -4
- package/src/zod/_test/FrameRequest.test-d.ts +15 -0
- package/src/zod/_test/FrameRequest.test.ts +44 -0
- package/src/zod/_test/FrameSignature.test.ts +73 -9
- package/src/zod/_test/RpcSchema.test.ts +106 -0
- package/src/zod/_test/TransactionRequest.test.ts +61 -0
- package/src/zod/_test/TxEnvelopeEip8141.nonce.test.ts +174 -0
- package/src/zod/_test/TxEnvelopeEip8141.test-d.ts +29 -0
- package/src/zod/_test/TxEnvelopeEip8141.test.ts +3 -3
- package/src/zod/internal/Frame.ts +45 -0
- package/src/zod/internal/rpcSchemas/Eth.ts +20 -0
- package/src/zod/z.ts +1 -0
|
@@ -6,12 +6,18 @@ import * as Frame from './Frame.js'
|
|
|
6
6
|
import * as FrameSignature from './FrameSignature.js'
|
|
7
7
|
import * as Hash from './Hash.js'
|
|
8
8
|
import * as Hex from './Hex.js'
|
|
9
|
+
import * as FrameNonce from './internal/frameNonce.js'
|
|
9
10
|
import * as Quantity from './internal/quantity.js'
|
|
10
11
|
import type { Assign, Compute, PartialBy } from './internal/types.js'
|
|
11
12
|
import * as Rlp from './Rlp.js'
|
|
12
13
|
import type * as TxEnvelopeEip4844 from './TxEnvelopeEip4844.js'
|
|
13
14
|
|
|
14
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* An EIP-8141 transaction containing independently budgeted call frames.
|
|
17
|
+
*
|
|
18
|
+
* Omitted `nonceKeys` preserves the original EIP-8141 encoding. Supplying keys,
|
|
19
|
+
* including `[0n]`, selects EIP-8250 encoding and changes the signing hash.
|
|
20
|
+
*/
|
|
15
21
|
export type TxEnvelopeEip8141 = {
|
|
16
22
|
/** Versioned blob hashes. @default [] */
|
|
17
23
|
blobVersionedHashes?: readonly Hex.Hex[] | undefined
|
|
@@ -25,8 +31,10 @@ export type TxEnvelopeEip8141 = {
|
|
|
25
31
|
maxFeePerGas?: bigint | undefined
|
|
26
32
|
/** Maximum priority fee per gas, in wei. @default 0n */
|
|
27
33
|
maxPriorityFeePerGas?: bigint | undefined
|
|
28
|
-
/** Sender nonce. @default 0n */
|
|
34
|
+
/** Sender nonce or shared sequence. With `nonceKeys`, the sequence must be less than 2^64 - 1. @default 0n */
|
|
29
35
|
nonce?: bigint | undefined
|
|
36
|
+
/** EIP-8250 domains: 1–16 strictly increasing uint256 keys. `[0n]` selects the legacy account nonce; zero cannot accompany other keys. */
|
|
37
|
+
nonceKeys?: readonly bigint[] | undefined
|
|
30
38
|
/** Account authorizing execution. */
|
|
31
39
|
sender: Address.Address
|
|
32
40
|
/** PeerDAS sidecars. Excluded from transaction and signing hashes. */
|
|
@@ -53,8 +61,10 @@ export type Rpc = {
|
|
|
53
61
|
maxFeePerGas: Hex.Hex
|
|
54
62
|
/** Maximum priority fee per gas. */
|
|
55
63
|
maxPriorityFeePerGas: Hex.Hex
|
|
56
|
-
/** Sender nonce. */
|
|
64
|
+
/** Sender nonce or shared EIP-8250 sequence. */
|
|
57
65
|
nonce: Hex.Hex
|
|
66
|
+
/** EIP-8250 domains. Omitted for the original EIP-8141 encoding. */
|
|
67
|
+
nonceKeys?: readonly Hex.Hex[] | undefined
|
|
58
68
|
/** Frame signature entries. */
|
|
59
69
|
signatures: readonly FrameSignature.Rpc[]
|
|
60
70
|
/** RPC transaction type. */
|
|
@@ -90,7 +100,7 @@ export type Type = typeof type
|
|
|
90
100
|
*
|
|
91
101
|
* TxEnvelopeEip8141.assert({
|
|
92
102
|
* chainId: 1,
|
|
93
|
-
* frames: [{
|
|
103
|
+
* frames: [{ executionGas: 50_000n, mode: 'verify' }],
|
|
94
104
|
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
95
105
|
* })
|
|
96
106
|
* ```
|
|
@@ -106,6 +116,7 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
|
106
116
|
maxFeePerGas = 0n,
|
|
107
117
|
maxPriorityFeePerGas = 0n,
|
|
108
118
|
nonce = 0n,
|
|
119
|
+
nonceKeys,
|
|
109
120
|
sender,
|
|
110
121
|
signatures = [],
|
|
111
122
|
} = envelope
|
|
@@ -118,6 +129,7 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
|
118
129
|
throw new InvalidError(
|
|
119
130
|
'chainId must be an unsigned 256-bit integer; use bigint for large IDs.',
|
|
120
131
|
)
|
|
132
|
+
if (nonceKeys !== undefined) FrameNonce.assert(nonceKeys, nonce)
|
|
121
133
|
Address.assert(sender, { strict: false })
|
|
122
134
|
for (const [field, value, bits] of [
|
|
123
135
|
['maxFeePerBlobGas', maxFeePerBlobGas, 256n],
|
|
@@ -146,7 +158,7 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
|
146
158
|
}
|
|
147
159
|
if (blobVersionedHashes.length === 0 && maxFeePerBlobGas !== 0n)
|
|
148
160
|
throw new InvalidError('maxFeePerBlobGas must be zero without blobs.')
|
|
149
|
-
let
|
|
161
|
+
let executionGas = 0n
|
|
150
162
|
let stateGas = 0n
|
|
151
163
|
let previousBatch = false
|
|
152
164
|
let expiry = false
|
|
@@ -157,6 +169,18 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
|
157
169
|
for (const byte of Hex.toBytes(data)) tokens += byte === 0 ? 1n : 4n
|
|
158
170
|
size += BigInt(Hex.size(data))
|
|
159
171
|
}
|
|
172
|
+
if (nonceKeys !== undefined) {
|
|
173
|
+
count(
|
|
174
|
+
Rlp.fromHex(
|
|
175
|
+
nonceKeys.map((key) =>
|
|
176
|
+
key === 0n ? '0x' : Hex.fromBytes(Bytes.fromNumber(key)),
|
|
177
|
+
),
|
|
178
|
+
),
|
|
179
|
+
)
|
|
180
|
+
count(
|
|
181
|
+
Rlp.fromHex(nonce === 0n ? '0x' : Hex.fromBytes(Bytes.fromNumber(nonce))),
|
|
182
|
+
)
|
|
183
|
+
}
|
|
160
184
|
for (const [index, frame] of (frames as readonly Frame.Frame[]).entries()) {
|
|
161
185
|
Frame.assert(frame)
|
|
162
186
|
const flags =
|
|
@@ -193,7 +217,7 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
|
193
217
|
throw new InvalidError('Invalid or duplicate expiry verifier frame.')
|
|
194
218
|
expiry = true
|
|
195
219
|
}
|
|
196
|
-
|
|
220
|
+
executionGas += frame.executionGas ?? 0n
|
|
197
221
|
stateGas += frame.stateGas ?? 0n
|
|
198
222
|
count(frame.data ?? '0x')
|
|
199
223
|
if (
|
|
@@ -210,10 +234,10 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
|
210
234
|
count(payload)
|
|
211
235
|
count(signature)
|
|
212
236
|
}
|
|
213
|
-
if (
|
|
237
|
+
if (executionGas + stateGas >= 2n ** 64n)
|
|
214
238
|
throw new InvalidError('Combined frame gas must be less than 2^64.')
|
|
215
239
|
if (
|
|
216
|
-
intrinsic + tokens * 4n +
|
|
240
|
+
intrinsic + tokens * 4n + executionGas > 16_777_216n ||
|
|
217
241
|
intrinsic + size * 64n > 16_777_216n
|
|
218
242
|
)
|
|
219
243
|
throw new InvalidError('Transaction execution gas exceeds 16777216.')
|
|
@@ -221,6 +245,7 @@ export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
|
221
245
|
export declare namespace assert {
|
|
222
246
|
type ErrorType =
|
|
223
247
|
| InvalidError
|
|
248
|
+
| FrameNonce.InvalidError
|
|
224
249
|
| Frame.assert.ErrorType
|
|
225
250
|
| FrameSignature.toTuple.ErrorType
|
|
226
251
|
| Address.assert.ErrorType
|
|
@@ -258,9 +283,14 @@ export function deserialize(serialized: Serialized): TxEnvelopeEip8141 {
|
|
|
258
283
|
throw new InvalidError('Expected a transaction list.')
|
|
259
284
|
const wrapped = Array.isArray(decoded[0])
|
|
260
285
|
const body = wrapped ? decoded[0] : decoded
|
|
261
|
-
if (!Array.isArray(body) || body.length !== 7)
|
|
262
|
-
throw new InvalidError('Expected seven transaction fields.')
|
|
263
|
-
const
|
|
286
|
+
if (!Array.isArray(body) || (body.length !== 7 && body.length !== 8))
|
|
287
|
+
throw new InvalidError('Expected seven or eight transaction fields.')
|
|
288
|
+
const keyed = body.length === 8
|
|
289
|
+
const [chainId, ...fields] = body
|
|
290
|
+
const keys = keyed ? fields.shift() : undefined
|
|
291
|
+
if (keyed && !Array.isArray(keys))
|
|
292
|
+
throw new InvalidError('Expected a nonce key list.')
|
|
293
|
+
const [nonce, sender, frames, signatures, fees, hashes] = fields
|
|
264
294
|
if (
|
|
265
295
|
typeof sender !== 'string' ||
|
|
266
296
|
!Array.isArray(frames) ||
|
|
@@ -288,6 +318,7 @@ export function deserialize(serialized: Serialized): TxEnvelopeEip8141 {
|
|
|
288
318
|
maxFeePerGas: integer(fees[1]),
|
|
289
319
|
maxPriorityFeePerGas: integer(fees[0]),
|
|
290
320
|
nonce: integer(nonce),
|
|
321
|
+
...(Array.isArray(keys) ? { nonceKeys: keys.map(integer) } : {}),
|
|
291
322
|
sender: sender as Address.Address,
|
|
292
323
|
signatures: signatures.map((entry) =>
|
|
293
324
|
FrameSignature.fromTuple(entry as FrameSignature.Tuple),
|
|
@@ -337,8 +368,8 @@ export declare namespace deserialize {
|
|
|
337
368
|
* chainId: 1,
|
|
338
369
|
* frames: [
|
|
339
370
|
* {
|
|
371
|
+
* executionGas: 50_000n,
|
|
340
372
|
* flags: 'approveExecutionAndPayment',
|
|
341
|
-
* gas: 50_000n,
|
|
342
373
|
* mode: 'verify'
|
|
343
374
|
* }
|
|
344
375
|
* ],
|
|
@@ -403,6 +434,9 @@ export function fromRpc(envelope: Rpc): TxEnvelopeEip8141 {
|
|
|
403
434
|
maxFeePerGas: Hex.toBigInt(envelope.maxFeePerGas),
|
|
404
435
|
maxPriorityFeePerGas: Hex.toBigInt(envelope.maxPriorityFeePerGas),
|
|
405
436
|
nonce: Hex.toBigInt(envelope.nonce),
|
|
437
|
+
...(envelope.nonceKeys !== undefined
|
|
438
|
+
? { nonceKeys: FrameNonce.fromRpc(envelope.nonceKeys, envelope.nonce) }
|
|
439
|
+
: {}),
|
|
406
440
|
sender: envelope.from,
|
|
407
441
|
signatures: envelope.signatures.map(FrameSignature.fromRpc),
|
|
408
442
|
})
|
|
@@ -410,6 +444,7 @@ export function fromRpc(envelope: Rpc): TxEnvelopeEip8141 {
|
|
|
410
444
|
|
|
411
445
|
export declare namespace fromRpc {
|
|
412
446
|
type ErrorType =
|
|
447
|
+
| FrameNonce.InvalidError
|
|
413
448
|
| from.ErrorType
|
|
414
449
|
| Frame.fromRpc.ErrorType
|
|
415
450
|
| FrameSignature.fromRpc.ErrorType
|
|
@@ -448,6 +483,9 @@ export function toRpc(envelope: toRpc.Input): Rpc {
|
|
|
448
483
|
envelope.maxPriorityFeePerGas ?? 0n,
|
|
449
484
|
),
|
|
450
485
|
nonce: Quantity.fromNumberish(envelope.nonce ?? 0n),
|
|
486
|
+
...(envelope.nonceKeys !== undefined
|
|
487
|
+
? { nonceKeys: FrameNonce.toRpc(envelope.nonceKeys, envelope.nonce) }
|
|
488
|
+
: {}),
|
|
451
489
|
signatures: (envelope.signatures ?? []).map(FrameSignature.toRpc),
|
|
452
490
|
type: '0x6',
|
|
453
491
|
}
|
|
@@ -462,6 +500,7 @@ export declare namespace toRpc {
|
|
|
462
500
|
| 'maxFeePerGas'
|
|
463
501
|
| 'maxPriorityFeePerGas'
|
|
464
502
|
| 'nonce'
|
|
503
|
+
| 'nonceKeys'
|
|
465
504
|
| 'type'
|
|
466
505
|
> & {
|
|
467
506
|
chainId: Hex.Hex | bigint | number
|
|
@@ -470,9 +509,11 @@ export declare namespace toRpc {
|
|
|
470
509
|
maxFeePerGas?: Hex.Hex | bigint | number | undefined
|
|
471
510
|
maxPriorityFeePerGas?: Hex.Hex | bigint | number | undefined
|
|
472
511
|
nonce?: Hex.Hex | bigint | number | undefined
|
|
512
|
+
nonceKeys?: readonly (Hex.Hex | bigint | number)[] | undefined
|
|
473
513
|
type?: Type | undefined
|
|
474
514
|
}
|
|
475
515
|
type ErrorType =
|
|
516
|
+
| FrameNonce.InvalidError
|
|
476
517
|
| Frame.toRpc.ErrorType
|
|
477
518
|
| FrameSignature.toRpc.ErrorType
|
|
478
519
|
| Hex.fromNumber.ErrorType
|
|
@@ -503,8 +544,8 @@ export declare namespace toRpc {
|
|
|
503
544
|
* chainId: 1,
|
|
504
545
|
* frames: [
|
|
505
546
|
* {
|
|
547
|
+
* executionGas: 50_000n,
|
|
506
548
|
* flags: 'approveExecutionAndPayment',
|
|
507
|
-
* gas: 50_000n,
|
|
508
549
|
* mode: 'verify'
|
|
509
550
|
* }
|
|
510
551
|
* ],
|
|
@@ -560,10 +601,12 @@ export function hash(
|
|
|
560
601
|
): Hex.Hex {
|
|
561
602
|
assert(envelope)
|
|
562
603
|
const body = toTuple(envelope)
|
|
563
|
-
if (options.presign)
|
|
564
|
-
body[
|
|
565
|
-
|
|
566
|
-
|
|
604
|
+
if (options.presign) {
|
|
605
|
+
const signatures = body.length === 8 ? body[5] : body[4]
|
|
606
|
+
for (const [index, entry] of signatures.entries())
|
|
607
|
+
if (entry[2] === '0x')
|
|
608
|
+
signatures[index] = [entry[0], entry[1], entry[2], '0x']
|
|
609
|
+
}
|
|
567
610
|
return Hash.keccak256(Hex.concat(serializedType, Rlp.fromHex(body)))
|
|
568
611
|
}
|
|
569
612
|
export declare namespace hash {
|
|
@@ -589,7 +632,7 @@ export declare namespace hash {
|
|
|
589
632
|
*
|
|
590
633
|
* const envelope = TxEnvelopeEip8141.from({
|
|
591
634
|
* chainId: 1,
|
|
592
|
-
* frames: [{
|
|
635
|
+
* frames: [{ executionGas: 50_000n, mode: 'sender' }],
|
|
593
636
|
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
594
637
|
* })
|
|
595
638
|
* const serialized = TxEnvelopeEip8141.serialize(envelope)
|
|
@@ -690,8 +733,7 @@ export class InvalidError extends Errors.BaseError {
|
|
|
690
733
|
function toTuple(envelope: PartialBy<TxEnvelopeEip8141, 'type'>) {
|
|
691
734
|
const quantity = (value: bigint | number | undefined): Hex.Hex =>
|
|
692
735
|
value ? Hex.fromBytes(Bytes.fromNumber(value)) : '0x'
|
|
693
|
-
|
|
694
|
-
quantity(envelope.chainId),
|
|
736
|
+
const fields = [
|
|
695
737
|
quantity(envelope.nonce),
|
|
696
738
|
envelope.sender,
|
|
697
739
|
envelope.frames.map((frame) => Frame.toTuple(frame)),
|
|
@@ -703,7 +745,6 @@ function toTuple(envelope: PartialBy<TxEnvelopeEip8141, 'type'>) {
|
|
|
703
745
|
],
|
|
704
746
|
envelope.blobVersionedHashes ?? [],
|
|
705
747
|
] satisfies [
|
|
706
|
-
Hex.Hex,
|
|
707
748
|
Hex.Hex,
|
|
708
749
|
Address.Address,
|
|
709
750
|
Frame.Tuple[],
|
|
@@ -711,4 +752,11 @@ function toTuple(envelope: PartialBy<TxEnvelopeEip8141, 'type'>) {
|
|
|
711
752
|
Hex.Hex[],
|
|
712
753
|
readonly Hex.Hex[],
|
|
713
754
|
]
|
|
755
|
+
return envelope.nonceKeys === undefined
|
|
756
|
+
? ([quantity(envelope.chainId), ...fields] as const)
|
|
757
|
+
: ([
|
|
758
|
+
quantity(envelope.chainId),
|
|
759
|
+
envelope.nonceKeys.map(quantity),
|
|
760
|
+
...fields,
|
|
761
|
+
] as const)
|
|
714
762
|
}
|
|
@@ -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.
|
|
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
|
-
|
|
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(
|
|
@@ -3,8 +3,8 @@ import { Rlp, Frame } from 'ox'
|
|
|
3
3
|
|
|
4
4
|
const frame = {
|
|
5
5
|
data: '0x',
|
|
6
|
+
executionGas: 50_000n,
|
|
6
7
|
flags: 3,
|
|
7
|
-
gas: 50_000n,
|
|
8
8
|
mode: 1,
|
|
9
9
|
stateGas: 0n,
|
|
10
10
|
value: 0n,
|
|
@@ -38,8 +38,8 @@ describe('toTuple', () => {
|
|
|
38
38
|
expect(
|
|
39
39
|
Frame.toTuple({
|
|
40
40
|
data: undefined,
|
|
41
|
+
executionGas: undefined,
|
|
41
42
|
flags: undefined,
|
|
42
|
-
gas: undefined,
|
|
43
43
|
mode: undefined,
|
|
44
44
|
stateGas: undefined,
|
|
45
45
|
value: undefined,
|
|
@@ -47,8 +47,8 @@ describe('toTuple', () => {
|
|
|
47
47
|
).toEqual(Frame.toTuple({}))
|
|
48
48
|
expect(
|
|
49
49
|
Frame.toTuple({
|
|
50
|
+
executionGas: 50_000n,
|
|
50
51
|
flags: 'approveExecutionAndPayment',
|
|
51
|
-
gas: 50_000n,
|
|
52
52
|
mode: 'verify',
|
|
53
53
|
}),
|
|
54
54
|
).toEqual(tuple)
|
|
@@ -95,9 +95,25 @@ describe('toTuple', () => {
|
|
|
95
95
|
)
|
|
96
96
|
})
|
|
97
97
|
|
|
98
|
+
test('preserves separate execution and state gas budgets', () => {
|
|
99
|
+
const frame = Frame.from({ executionGas: 50_000n, stateGas: 12n })
|
|
100
|
+
const tuple = Frame.toTuple(frame)
|
|
101
|
+
expect(tuple).toEqual(['0x', '0x', '0x', ['0xc350', '0x0c'], '0x', '0x'])
|
|
102
|
+
expect(Frame.fromTuple(tuple)).toEqual({
|
|
103
|
+
data: '0x',
|
|
104
|
+
executionGas: 50_000n,
|
|
105
|
+
flags: 0,
|
|
106
|
+
mode: 0,
|
|
107
|
+
stateGas: 12n,
|
|
108
|
+
value: 0n,
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
98
112
|
test('encodes zero integers as empty bytes', () => {
|
|
99
113
|
expect(
|
|
100
|
-
Rlp.fromHex(
|
|
114
|
+
Rlp.fromHex(
|
|
115
|
+
Frame.toTuple({ ...frame, executionGas: 0n, flags: 0, mode: 0 }),
|
|
116
|
+
),
|
|
101
117
|
).toMatchInlineSnapshot('"0xc8808080c280808080"')
|
|
102
118
|
})
|
|
103
119
|
|
|
@@ -105,8 +121,8 @@ describe('toTuple', () => {
|
|
|
105
121
|
const input = {
|
|
106
122
|
...frame,
|
|
107
123
|
data: '0x0001',
|
|
124
|
+
executionGas: 2n ** 63n,
|
|
108
125
|
flags: 0,
|
|
109
|
-
gas: 2n ** 63n,
|
|
110
126
|
mode: 2,
|
|
111
127
|
stateGas: 2n ** 63n - 1n,
|
|
112
128
|
value: 2n ** 256n - 1n,
|
|
@@ -158,10 +174,20 @@ describe('fromTuple', () => {
|
|
|
158
174
|
})
|
|
159
175
|
|
|
160
176
|
describe('assert', () => {
|
|
177
|
+
test('reports the execution gas field', () => {
|
|
178
|
+
expect(() =>
|
|
179
|
+
Frame.assert({ executionGas: -1n }),
|
|
180
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
181
|
+
`[Frame.InvalidError: Invalid frame.
|
|
182
|
+
|
|
183
|
+
Details: executionGas must be an unsigned 64-bit integer.]`,
|
|
184
|
+
)
|
|
185
|
+
})
|
|
186
|
+
|
|
161
187
|
test.each([
|
|
162
188
|
{ data: null },
|
|
163
189
|
{ flags: null },
|
|
164
|
-
{
|
|
190
|
+
{ executionGas: null },
|
|
165
191
|
{ mode: null },
|
|
166
192
|
{ stateGas: null },
|
|
167
193
|
{ value: null },
|
|
@@ -185,11 +211,11 @@ describe('assert', () => {
|
|
|
185
211
|
{ value: 1n },
|
|
186
212
|
{ mode: 2, value: -1n },
|
|
187
213
|
{ mode: 2, value: 2n ** 256n },
|
|
188
|
-
{
|
|
189
|
-
{
|
|
214
|
+
{ executionGas: -1n },
|
|
215
|
+
{ executionGas: 2n ** 64n },
|
|
190
216
|
{ stateGas: -1n },
|
|
191
217
|
{ stateGas: 2n ** 64n },
|
|
192
|
-
{
|
|
218
|
+
{ executionGas: 2n ** 64n - 1n, stateGas: 1n },
|
|
193
219
|
{ data: '0x0' },
|
|
194
220
|
{ data: '0xgg' },
|
|
195
221
|
{ to: '0x01' },
|
|
@@ -221,19 +247,19 @@ describe('fromRpc', () => {
|
|
|
221
247
|
expect(
|
|
222
248
|
Frame.fromRpc({
|
|
223
249
|
data: '0xdeadbeef',
|
|
224
|
-
|
|
225
|
-
flags:
|
|
226
|
-
mode:
|
|
227
|
-
|
|
250
|
+
executionGas: '0x20000000000001',
|
|
251
|
+
flags: '0x0',
|
|
252
|
+
mode: '0x2',
|
|
253
|
+
stateGas: '0xc',
|
|
228
254
|
target: null,
|
|
229
255
|
value: '0x1',
|
|
230
256
|
}),
|
|
231
257
|
).toEqual({
|
|
232
258
|
data: '0xdeadbeef',
|
|
259
|
+
executionGas: 9007199254740993n,
|
|
233
260
|
flags: 0,
|
|
234
|
-
gas: 9007199254740993n,
|
|
235
261
|
mode: 2,
|
|
236
|
-
stateGas:
|
|
262
|
+
stateGas: 12n,
|
|
237
263
|
value: 1n,
|
|
238
264
|
})
|
|
239
265
|
})
|
|
@@ -247,20 +273,22 @@ describe('toRpc', () => {
|
|
|
247
273
|
),
|
|
248
274
|
).toEqual({
|
|
249
275
|
data: '0x',
|
|
250
|
-
|
|
251
|
-
flags:
|
|
252
|
-
mode:
|
|
253
|
-
|
|
276
|
+
executionGas: '0x0',
|
|
277
|
+
flags: '0x3',
|
|
278
|
+
mode: '0x1',
|
|
279
|
+
stateGas: '0x0',
|
|
254
280
|
value: '0x0',
|
|
255
281
|
})
|
|
256
282
|
})
|
|
257
283
|
test('accepts numberish budgets', () => {
|
|
258
|
-
expect(
|
|
284
|
+
expect(
|
|
285
|
+
Frame.toRpc({ executionGas: '0xc350', stateGas: 12, value: 0n }),
|
|
286
|
+
).toEqual({
|
|
259
287
|
data: '0x',
|
|
260
|
-
|
|
261
|
-
flags:
|
|
262
|
-
mode:
|
|
263
|
-
|
|
288
|
+
executionGas: '0xc350',
|
|
289
|
+
flags: '0x0',
|
|
290
|
+
mode: '0x0',
|
|
291
|
+
stateGas: '0xc',
|
|
264
292
|
value: '0x0',
|
|
265
293
|
})
|
|
266
294
|
})
|
|
@@ -14,13 +14,14 @@ test('exports', () => {
|
|
|
14
14
|
|
|
15
15
|
describe('fromRpc', () => {
|
|
16
16
|
test.each([
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[
|
|
17
|
+
['0x0', 'reverted'],
|
|
18
|
+
['0x1', 'success'],
|
|
19
|
+
['0x2', 'skipped'],
|
|
20
20
|
] as const)('status %s', (status, expected) => {
|
|
21
21
|
expect(
|
|
22
22
|
FrameReceipt.fromRpc({
|
|
23
23
|
executionGasUsed: '0x20000000000001',
|
|
24
|
+
gasUsed: '0x20000000000003',
|
|
24
25
|
logs: [
|
|
25
26
|
{
|
|
26
27
|
address: '0x1111111111111111111111111111111111111111',
|
|
@@ -32,7 +33,8 @@ describe('fromRpc', () => {
|
|
|
32
33
|
status,
|
|
33
34
|
}),
|
|
34
35
|
).toEqual({
|
|
35
|
-
|
|
36
|
+
executionGasUsed: 9007199254740993n,
|
|
37
|
+
gasUsed: 9007199254740995n,
|
|
36
38
|
logs: [
|
|
37
39
|
{
|
|
38
40
|
address: '0x1111111111111111111111111111111111111111',
|
|
@@ -48,18 +50,20 @@ describe('fromRpc', () => {
|
|
|
48
50
|
|
|
49
51
|
describe('toRpc', () => {
|
|
50
52
|
test.each([
|
|
51
|
-
['reverted',
|
|
52
|
-
['success',
|
|
53
|
-
['skipped',
|
|
53
|
+
['reverted', '0x0'],
|
|
54
|
+
['success', '0x1'],
|
|
55
|
+
['skipped', '0x2'],
|
|
54
56
|
] as const)('status %s', (status, expected) => {
|
|
55
57
|
const receipt = FrameReceipt.fromRpc({
|
|
56
58
|
executionGasUsed: '0x20000000000001',
|
|
59
|
+
gasUsed: '0x20000000000003',
|
|
57
60
|
logs: [],
|
|
58
61
|
stateGasUsed: '0x2',
|
|
59
62
|
status: expected,
|
|
60
63
|
})
|
|
61
64
|
expect(FrameReceipt.toRpc({ ...receipt, status })).toEqual({
|
|
62
65
|
executionGasUsed: '0x20000000000001',
|
|
66
|
+
gasUsed: '0x20000000000003',
|
|
63
67
|
logs: [],
|
|
64
68
|
stateGasUsed: '0x2',
|
|
65
69
|
status: expected,
|
|
@@ -69,7 +73,8 @@ describe('toRpc', () => {
|
|
|
69
73
|
test('numberish gas', () => {
|
|
70
74
|
expect(
|
|
71
75
|
FrameReceipt.toRpc({
|
|
72
|
-
|
|
76
|
+
executionGasUsed: '0x5208',
|
|
77
|
+
gasUsed: '0x520a',
|
|
73
78
|
logs: [],
|
|
74
79
|
stateGasUsed: 2,
|
|
75
80
|
status: 'success',
|
|
@@ -77,9 +82,10 @@ describe('toRpc', () => {
|
|
|
77
82
|
).toMatchInlineSnapshot(`
|
|
78
83
|
{
|
|
79
84
|
"executionGasUsed": "0x5208",
|
|
85
|
+
"gasUsed": "0x520a",
|
|
80
86
|
"logs": [],
|
|
81
87
|
"stateGasUsed": "0x2",
|
|
82
|
-
"status":
|
|
88
|
+
"status": "0x1",
|
|
83
89
|
}
|
|
84
90
|
`)
|
|
85
91
|
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FrameRequest } from 'ox'
|
|
2
|
+
import { expectTypeOf, test } from 'vp/test'
|
|
3
|
+
|
|
4
|
+
test('public frame request types', () => {
|
|
5
|
+
const rpc = { mode: '0x2' } as const satisfies FrameRequest.Rpc
|
|
6
|
+
const request = FrameRequest.fromRpc(rpc)
|
|
7
|
+
expectTypeOf(request).toEqualTypeOf<FrameRequest.FrameRequest>()
|
|
8
|
+
expectTypeOf(FrameRequest.toRpc(request)).toEqualTypeOf<FrameRequest.Rpc>()
|
|
9
|
+
const input = {
|
|
10
|
+
executionGas: '0x1',
|
|
11
|
+
stateGas: 0,
|
|
12
|
+
} as const satisfies FrameRequest.toRpc.Input
|
|
13
|
+
expectTypeOf(FrameRequest.toRpc(input)).toEqualTypeOf<FrameRequest.Rpc>()
|
|
14
|
+
expectTypeOf<FrameRequest.fromRpc.ErrorType>().not.toBeNever()
|
|
15
|
+
expectTypeOf<FrameRequest.toRpc.ErrorType>().not.toBeNever()
|
|
16
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { FrameRequest } from 'ox'
|
|
2
|
+
import { describe, expect, test } from 'vp/test'
|
|
3
|
+
|
|
4
|
+
test('exports', () => {
|
|
5
|
+
expect(Object.keys(FrameRequest).sort()).toMatchInlineSnapshot(`
|
|
6
|
+
[
|
|
7
|
+
"fromRpc",
|
|
8
|
+
"toRpc",
|
|
9
|
+
]
|
|
10
|
+
`)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe('fromRpc', () => {
|
|
14
|
+
test('preserves omitted execution gas and explicit zero state gas', () => {
|
|
15
|
+
expect(FrameRequest.fromRpc({ mode: '0x2', stateGas: '0x0' }))
|
|
16
|
+
.toMatchInlineSnapshot(`
|
|
17
|
+
{
|
|
18
|
+
"data": "0x",
|
|
19
|
+
"flags": 0,
|
|
20
|
+
"mode": 2,
|
|
21
|
+
"stateGas": 0n,
|
|
22
|
+
"value": 0n,
|
|
23
|
+
}
|
|
24
|
+
`)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('toRpc', () => {
|
|
29
|
+
test('preserves omitted gas and encodes numberish values', () => {
|
|
30
|
+
expect(FrameRequest.toRpc({ mode: 'sender', stateGas: 0, value: '0x1' }))
|
|
31
|
+
.toMatchInlineSnapshot(`
|
|
32
|
+
{
|
|
33
|
+
"data": "0x",
|
|
34
|
+
"flags": "0x0",
|
|
35
|
+
"mode": "0x2",
|
|
36
|
+
"stateGas": "0x0",
|
|
37
|
+
"value": "0x1",
|
|
38
|
+
}
|
|
39
|
+
`)
|
|
40
|
+
})
|
|
41
|
+
})
|