ox 1.7.4 → 1.8.0
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 +22 -0
- package/dist/core/AbiEvent.d.ts.map +1 -1
- package/dist/core/AbiEvent.js +10 -9
- package/dist/core/AbiEvent.js.map +1 -1
- package/dist/core/Blobs.d.ts.map +1 -1
- package/dist/core/Blobs.js +6 -2
- package/dist/core/Blobs.js.map +1 -1
- 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/Signature.d.ts +6 -5
- package/dist/core/Signature.d.ts.map +1 -1
- package/dist/core/Signature.js +17 -7
- package/dist/core/Signature.js.map +1 -1
- package/dist/core/Siwe.d.ts.map +1 -1
- package/dist/core/Siwe.js +21 -1
- package/dist/core/Siwe.js.map +1 -1
- 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 +485 -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/KeyAuthorization.d.ts +42 -38
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/KeyAuthorization.js +24 -4
- package/dist/tempo/KeyAuthorization.js.map +1 -1
- package/dist/tempo/MultisigConfig.d.ts +18 -15
- package/dist/tempo/MultisigConfig.d.ts.map +1 -1
- package/dist/tempo/MultisigConfig.js +49 -20
- package/dist/tempo/MultisigConfig.js.map +1 -1
- package/dist/tempo/MultisigOperation.d.ts +3 -2
- package/dist/tempo/MultisigOperation.d.ts.map +1 -1
- package/dist/tempo/MultisigOperation.js +20 -100
- package/dist/tempo/MultisigOperation.js.map +1 -1
- package/dist/tempo/MultisigSimulation.d.ts +2 -49
- package/dist/tempo/MultisigSimulation.d.ts.map +1 -1
- package/dist/tempo/MultisigSimulation.js +18 -46
- package/dist/tempo/MultisigSimulation.js.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +72 -140
- package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/tempo/SignatureEnvelope.js +130 -181
- package/dist/tempo/SignatureEnvelope.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/tempo/TransactionRequest.d.ts +4 -2
- package/dist/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/tempo/TransactionRequest.js +6 -1
- package/dist/tempo/TransactionRequest.js.map +1 -1
- package/dist/tempo/index.d.ts +3 -1
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +3 -1
- package/dist/tempo/index.js.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/AuthorizationTempo.d.ts +350 -10
- package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.d.ts +242 -422
- package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.js +29 -31
- package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
- package/dist/zod/tempo/MultisigSimulation.d.ts +8 -76
- package/dist/zod/tempo/MultisigSimulation.d.ts.map +1 -1
- package/dist/zod/tempo/MultisigSimulation.js +3 -37
- package/dist/zod/tempo/MultisigSimulation.js.map +1 -1
- package/dist/zod/tempo/RpcSchemaTempo.d.ts +424 -228
- package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.d.ts +105 -3
- package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.js +21 -9
- package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/zod/tempo/Transaction.d.ts +783 -432
- package/dist/zod/tempo/Transaction.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.d.ts +590 -473
- package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.js +8 -0
- package/dist/zod/tempo/TransactionRequest.js.map +1 -1
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts +327 -213
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
- package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +105 -3
- package/dist/zod/tempo/ZoneRpcAuthentication.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/AbiEvent.ts +11 -9
- package/src/core/Blobs.ts +6 -2
- package/src/core/Frame.ts +443 -0
- package/src/core/FrameReceipt.ts +117 -0
- package/src/core/FrameSignature.ts +593 -0
- package/src/core/Signature.ts +41 -11
- package/src/core/Siwe.ts +20 -1
- 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 +715 -0
- package/src/core/_test/AbiEvent.test.ts +45 -0
- package/src/core/_test/Blobs.test.ts +22 -0
- package/src/core/_test/Frame.test-d.ts +96 -0
- package/src/core/_test/Frame.test.ts +267 -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/Signature.test.ts +166 -0
- package/src/core/_test/Siwe.test.ts +100 -1
- 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/tempo/AuthorizationTempo.test.ts +8 -4
- package/src/tempo/KeyAuthorization.test-d.ts +16 -63
- package/src/tempo/KeyAuthorization.test.ts +69 -11
- package/src/tempo/KeyAuthorization.ts +107 -63
- package/src/tempo/MultisigConfig.test.ts +44 -20
- package/src/tempo/MultisigConfig.ts +65 -23
- package/src/tempo/MultisigOperation.test.ts +79 -550
- package/src/tempo/MultisigOperation.ts +31 -146
- package/src/tempo/MultisigSimulation.test-d.ts +2 -2
- package/src/tempo/MultisigSimulation.test.ts +21 -110
- package/src/tempo/MultisigSimulation.ts +25 -99
- package/src/tempo/SignatureEnvelope.test-d.ts +29 -47
- package/src/tempo/SignatureEnvelope.test.ts +328 -541
- package/src/tempo/SignatureEnvelope.ts +196 -291
- package/src/tempo/Transaction.test.ts +4 -4
- package/src/tempo/TransactionRequest.test.ts +17 -80
- package/src/tempo/TransactionRequest.ts +19 -2
- package/src/tempo/index.ts +3 -1
- package/src/tempo/multisig.e2e.test.ts +321 -860
- 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 +54 -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/tempo/KeyAuthorization.ts +50 -39
- package/src/zod/tempo/MultisigSimulation.ts +3 -48
- package/src/zod/tempo/SignatureEnvelope.ts +46 -35
- package/src/zod/tempo/TransactionRequest.ts +14 -0
- package/src/zod/tempo/_test/KeyAuthorization.test.ts +69 -20
- package/src/zod/tempo/_test/MultisigSimulation.test.ts +6 -31
- package/src/zod/tempo/_test/SignatureEnvelope.test.ts +118 -85
- package/src/zod/tempo/_test/TransactionRequest.test.ts +9 -19
- package/src/zod/z.ts +4 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
import * as Address from './Address.js'
|
|
2
|
+
import * as Blobs from './Blobs.js'
|
|
3
|
+
import * as Bytes from './Bytes.js'
|
|
4
|
+
import * as Errors from './Errors.js'
|
|
5
|
+
import * as Frame from './Frame.js'
|
|
6
|
+
import * as FrameSignature from './FrameSignature.js'
|
|
7
|
+
import * as Hash from './Hash.js'
|
|
8
|
+
import * as Hex from './Hex.js'
|
|
9
|
+
import * as Quantity from './internal/quantity.js'
|
|
10
|
+
import type { Assign, Compute, PartialBy } from './internal/types.js'
|
|
11
|
+
import * as Rlp from './Rlp.js'
|
|
12
|
+
import type * as TxEnvelopeEip4844 from './TxEnvelopeEip4844.js'
|
|
13
|
+
|
|
14
|
+
/** An EIP-8141 transaction containing independently budgeted call frames. */
|
|
15
|
+
export type TxEnvelopeEip8141 = {
|
|
16
|
+
/** Versioned blob hashes. @default [] */
|
|
17
|
+
blobVersionedHashes?: readonly Hex.Hex[] | undefined
|
|
18
|
+
/** Chain ID. Use bigint for IDs beyond the safe integer range. */
|
|
19
|
+
chainId: number | bigint
|
|
20
|
+
/** Frames to execute, in order. */
|
|
21
|
+
frames: readonly Frame.Frame[]
|
|
22
|
+
/** Maximum fee per blob gas, in wei. @default 0n */
|
|
23
|
+
maxFeePerBlobGas?: bigint | undefined
|
|
24
|
+
/** Maximum fee per gas, in wei. @default 0n */
|
|
25
|
+
maxFeePerGas?: bigint | undefined
|
|
26
|
+
/** Maximum priority fee per gas, in wei. @default 0n */
|
|
27
|
+
maxPriorityFeePerGas?: bigint | undefined
|
|
28
|
+
/** Sender nonce. @default 0n */
|
|
29
|
+
nonce?: bigint | undefined
|
|
30
|
+
/** Account authorizing execution. */
|
|
31
|
+
sender: Address.Address
|
|
32
|
+
/** PeerDAS sidecars. Excluded from transaction and signing hashes. */
|
|
33
|
+
sidecars?: TxEnvelopeEip4844.Sidecars<Hex.Hex> | undefined
|
|
34
|
+
/** Signature entries, including unsigned placeholders before signing. @default [] */
|
|
35
|
+
signatures?: readonly FrameSignature.FrameSignature[] | undefined
|
|
36
|
+
/** Transaction type. */
|
|
37
|
+
type: Type
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** JSON-RPC representation of an EIP-8141 envelope. */
|
|
41
|
+
export type Rpc = {
|
|
42
|
+
/** Versioned blob hashes. */
|
|
43
|
+
blobVersionedHashes: readonly Hex.Hex[]
|
|
44
|
+
/** Chain ID. */
|
|
45
|
+
chainId: Hex.Hex
|
|
46
|
+
/** Frames in execution order. */
|
|
47
|
+
frames: readonly Frame.Rpc[]
|
|
48
|
+
/** Account authorizing execution. */
|
|
49
|
+
from: Address.Address
|
|
50
|
+
/** Maximum fee per blob gas. */
|
|
51
|
+
maxFeePerBlobGas: Hex.Hex
|
|
52
|
+
/** Maximum fee per gas. */
|
|
53
|
+
maxFeePerGas: Hex.Hex
|
|
54
|
+
/** Maximum priority fee per gas. */
|
|
55
|
+
maxPriorityFeePerGas: Hex.Hex
|
|
56
|
+
/** Sender nonce. */
|
|
57
|
+
nonce: Hex.Hex
|
|
58
|
+
/** Frame signature entries. */
|
|
59
|
+
signatures: readonly FrameSignature.Rpc[]
|
|
60
|
+
/** RPC transaction type. */
|
|
61
|
+
type: '0x6'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Serialized EIP-8141 transaction envelope. */
|
|
65
|
+
export type Serialized = `${SerializedType}${string}`
|
|
66
|
+
|
|
67
|
+
/** Serialized EIP-8141 transaction type prefix. */
|
|
68
|
+
export const serializedType = '0x06' as const
|
|
69
|
+
|
|
70
|
+
/** Serialized EIP-8141 transaction type. */
|
|
71
|
+
export type SerializedType = typeof serializedType
|
|
72
|
+
|
|
73
|
+
/** EIP-8141 transaction type. */
|
|
74
|
+
export const type = 'eip8141' as const
|
|
75
|
+
|
|
76
|
+
/** EIP-8141 transaction type identifier. */
|
|
77
|
+
export type Type = typeof type
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Asserts that an EIP-8141 envelope satisfies structural transaction constraints.
|
|
81
|
+
*
|
|
82
|
+
* Accepts unsigned signature entries for construction. Does not verify signatures,
|
|
83
|
+
* account authorization, balances, or blob proofs.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ### Basic Usage
|
|
87
|
+
*
|
|
88
|
+
* ```ts twoslash
|
|
89
|
+
* import { TxEnvelopeEip8141 } from 'ox'
|
|
90
|
+
*
|
|
91
|
+
* TxEnvelopeEip8141.assert({
|
|
92
|
+
* chainId: 1,
|
|
93
|
+
* frames: [{ gas: 50_000n, mode: 'verify' }],
|
|
94
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
95
|
+
* })
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @param envelope - The transaction envelope to assert.
|
|
99
|
+
*/
|
|
100
|
+
export function assert(envelope: PartialBy<TxEnvelopeEip8141, 'type'>): void {
|
|
101
|
+
const {
|
|
102
|
+
blobVersionedHashes = [],
|
|
103
|
+
chainId,
|
|
104
|
+
frames,
|
|
105
|
+
maxFeePerBlobGas = 0n,
|
|
106
|
+
maxFeePerGas = 0n,
|
|
107
|
+
maxPriorityFeePerGas = 0n,
|
|
108
|
+
nonce = 0n,
|
|
109
|
+
sender,
|
|
110
|
+
signatures = [],
|
|
111
|
+
} = envelope
|
|
112
|
+
if (
|
|
113
|
+
(typeof chainId !== 'bigint' &&
|
|
114
|
+
(typeof chainId !== 'number' || !Number.isSafeInteger(chainId))) ||
|
|
115
|
+
BigInt(chainId) < 0n ||
|
|
116
|
+
BigInt(chainId) >= 2n ** 256n
|
|
117
|
+
)
|
|
118
|
+
throw new InvalidError(
|
|
119
|
+
'chainId must be an unsigned 256-bit integer; use bigint for large IDs.',
|
|
120
|
+
)
|
|
121
|
+
Address.assert(sender, { strict: false })
|
|
122
|
+
for (const [field, value, bits] of [
|
|
123
|
+
['maxFeePerBlobGas', maxFeePerBlobGas, 256n],
|
|
124
|
+
['maxFeePerGas', maxFeePerGas, 256n],
|
|
125
|
+
['maxPriorityFeePerGas', maxPriorityFeePerGas, 256n],
|
|
126
|
+
['nonce', nonce, 64n],
|
|
127
|
+
] as const)
|
|
128
|
+
if (typeof value !== 'bigint' || value < 0n || value >= 2n ** bits)
|
|
129
|
+
throw new InvalidError(
|
|
130
|
+
`${field} must be an unsigned ${bits}-bit integer.`,
|
|
131
|
+
)
|
|
132
|
+
if (maxPriorityFeePerGas > maxFeePerGas)
|
|
133
|
+
throw new InvalidError('maxPriorityFeePerGas exceeds maxFeePerGas.')
|
|
134
|
+
if (!Array.isArray(frames) || frames.length === 0 || frames.length > 64)
|
|
135
|
+
throw new InvalidError('Expected between 1 and 64 frames.')
|
|
136
|
+
if (!Array.isArray(signatures) || !Array.isArray(blobVersionedHashes))
|
|
137
|
+
throw new InvalidError(
|
|
138
|
+
'Signatures and blob versioned hashes must be lists.',
|
|
139
|
+
)
|
|
140
|
+
for (const hash of blobVersionedHashes) {
|
|
141
|
+
Hex.assert(hash, { strict: true })
|
|
142
|
+
if (hash.length !== 66 || Hex.slice(hash, 0, 1) !== '0x01')
|
|
143
|
+
throw new InvalidError(
|
|
144
|
+
'Blob versioned hashes must contain 32 bytes and version 0x01.',
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
if (blobVersionedHashes.length === 0 && maxFeePerBlobGas !== 0n)
|
|
148
|
+
throw new InvalidError('maxFeePerBlobGas must be zero without blobs.')
|
|
149
|
+
let gas = 0n
|
|
150
|
+
let stateGas = 0n
|
|
151
|
+
let previousBatch = false
|
|
152
|
+
let expiry = false
|
|
153
|
+
let tokens = 0n
|
|
154
|
+
let size = 0n
|
|
155
|
+
let intrinsic = 12_000n + BigInt(frames.length) * 475n
|
|
156
|
+
const count = (data: Hex.Hex) => {
|
|
157
|
+
for (const byte of Hex.toBytes(data)) tokens += byte === 0 ? 1n : 4n
|
|
158
|
+
size += BigInt(Hex.size(data))
|
|
159
|
+
}
|
|
160
|
+
for (const [index, frame] of (frames as readonly Frame.Frame[]).entries()) {
|
|
161
|
+
Frame.assert(frame)
|
|
162
|
+
const flags =
|
|
163
|
+
typeof frame.flags === 'string'
|
|
164
|
+
? Frame.flags[frame.flags]
|
|
165
|
+
: (frame.flags ?? 0)
|
|
166
|
+
const batch = (flags & 4) !== 0
|
|
167
|
+
if (
|
|
168
|
+
flags & 2 &&
|
|
169
|
+
frame.target !== undefined &&
|
|
170
|
+
!Address.isEqual(frame.target, sender)
|
|
171
|
+
)
|
|
172
|
+
throw new InvalidError('Execution approval must target the sender.')
|
|
173
|
+
if ((batch || previousBatch) && flags & 3)
|
|
174
|
+
throw new InvalidError('Atomic batches cannot contain approval frames.')
|
|
175
|
+
if (batch) {
|
|
176
|
+
const next = frames[index + 1]
|
|
177
|
+
if (!next || next.mode === 1 || next.mode === 'verify')
|
|
178
|
+
throw new InvalidError(
|
|
179
|
+
'An atomic batch requires a following non-verify frame.',
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
previousBatch = batch
|
|
183
|
+
if (
|
|
184
|
+
(frame.mode === 1 || frame.mode === 'verify') &&
|
|
185
|
+
frame.target?.toLowerCase() ===
|
|
186
|
+
'0x0000000000000000000000000000000000008141'
|
|
187
|
+
) {
|
|
188
|
+
if (
|
|
189
|
+
expiry ||
|
|
190
|
+
flags !== 0 ||
|
|
191
|
+
(frame.stateGas ?? 0n) !== 0n ||
|
|
192
|
+
Hex.size(frame.data ?? '0x') !== 8
|
|
193
|
+
)
|
|
194
|
+
throw new InvalidError('Invalid or duplicate expiry verifier frame.')
|
|
195
|
+
expiry = true
|
|
196
|
+
}
|
|
197
|
+
gas += frame.gas ?? 0n
|
|
198
|
+
stateGas += frame.stateGas ?? 0n
|
|
199
|
+
count(frame.data ?? '0x')
|
|
200
|
+
if (
|
|
201
|
+
(frame.value ?? 0n) > 0n &&
|
|
202
|
+
frame.target !== undefined &&
|
|
203
|
+
!Address.isEqual(frame.target, sender)
|
|
204
|
+
)
|
|
205
|
+
intrinsic += 6_000n
|
|
206
|
+
}
|
|
207
|
+
for (const entry of signatures) {
|
|
208
|
+
const [scheme, signer, payload, signature] = FrameSignature.toTuple(entry)
|
|
209
|
+
intrinsic += scheme === '0x' ? 100n : scheme === '0x01' ? 2_800n : 6_700n
|
|
210
|
+
count(signer)
|
|
211
|
+
count(payload)
|
|
212
|
+
count(signature)
|
|
213
|
+
}
|
|
214
|
+
if (gas + stateGas >= 2n ** 64n)
|
|
215
|
+
throw new InvalidError('Combined frame gas must be less than 2^64.')
|
|
216
|
+
if (
|
|
217
|
+
intrinsic + tokens * 4n + gas > 16_777_216n ||
|
|
218
|
+
intrinsic + size * 64n > 16_777_216n
|
|
219
|
+
)
|
|
220
|
+
throw new InvalidError('Transaction execution gas exceeds 16777216.')
|
|
221
|
+
}
|
|
222
|
+
export declare namespace assert {
|
|
223
|
+
type ErrorType =
|
|
224
|
+
| InvalidError
|
|
225
|
+
| Frame.assert.ErrorType
|
|
226
|
+
| FrameSignature.toTuple.ErrorType
|
|
227
|
+
| Address.assert.ErrorType
|
|
228
|
+
| Errors.GlobalErrorType
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Deserializes an EIP-8141 transaction body or PeerDAS network wrapper.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ### Basic Usage
|
|
236
|
+
*
|
|
237
|
+
* ```ts twoslash
|
|
238
|
+
* import { Frame, TxEnvelopeEip8141 } from 'ox'
|
|
239
|
+
*
|
|
240
|
+
* const envelope = TxEnvelopeEip8141.from({
|
|
241
|
+
* chainId: 1,
|
|
242
|
+
* frames: [Frame.from({})],
|
|
243
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
244
|
+
* })
|
|
245
|
+
*
|
|
246
|
+
* const serialized = TxEnvelopeEip8141.serialize(envelope)
|
|
247
|
+
* const decoded = TxEnvelopeEip8141.deserialize(serialized)
|
|
248
|
+
* ```
|
|
249
|
+
*
|
|
250
|
+
* @param serialized - Serialized transaction or network wrapper.
|
|
251
|
+
* @returns The transaction envelope.
|
|
252
|
+
*/
|
|
253
|
+
export function deserialize(serialized: Serialized): TxEnvelopeEip8141 {
|
|
254
|
+
Hex.assert(serialized, { strict: true })
|
|
255
|
+
if (Hex.slice(serialized, 0, 1) !== serializedType)
|
|
256
|
+
throw new InvalidError('Expected transaction type 0x06.')
|
|
257
|
+
const decoded = Rlp.toHex(Hex.slice(serialized, 1))
|
|
258
|
+
if (!Array.isArray(decoded))
|
|
259
|
+
throw new InvalidError('Expected a transaction list.')
|
|
260
|
+
const wrapped = Array.isArray(decoded[0])
|
|
261
|
+
const body = wrapped ? decoded[0] : decoded
|
|
262
|
+
if (!Array.isArray(body) || body.length !== 7)
|
|
263
|
+
throw new InvalidError('Expected seven transaction fields.')
|
|
264
|
+
const [chainId, nonce, sender, frames, signatures, fees, hashes] = body
|
|
265
|
+
if (
|
|
266
|
+
typeof sender !== 'string' ||
|
|
267
|
+
!Array.isArray(frames) ||
|
|
268
|
+
!Array.isArray(signatures) ||
|
|
269
|
+
!Array.isArray(fees) ||
|
|
270
|
+
fees.length !== 3 ||
|
|
271
|
+
!Array.isArray(hashes) ||
|
|
272
|
+
hashes.some((hash) => typeof hash !== 'string')
|
|
273
|
+
)
|
|
274
|
+
throw new InvalidError('Invalid transaction field shape.')
|
|
275
|
+
const integer = (value: unknown): bigint => {
|
|
276
|
+
if (
|
|
277
|
+
typeof value !== 'string' ||
|
|
278
|
+
(value !== '0x' && value.startsWith('0x00'))
|
|
279
|
+
)
|
|
280
|
+
throw new InvalidError('Expected a minimally encoded integer.')
|
|
281
|
+
return value === '0x' ? 0n : Hex.toBigInt(value as Hex.Hex)
|
|
282
|
+
}
|
|
283
|
+
const id = integer(chainId)
|
|
284
|
+
const envelope: TxEnvelopeEip8141 = {
|
|
285
|
+
blobVersionedHashes: hashes as Hex.Hex[],
|
|
286
|
+
chainId: id <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(id) : id,
|
|
287
|
+
frames: frames.map((frame) => Frame.fromTuple(frame as Frame.Tuple)),
|
|
288
|
+
maxFeePerBlobGas: integer(fees[2]),
|
|
289
|
+
maxFeePerGas: integer(fees[1]),
|
|
290
|
+
maxPriorityFeePerGas: integer(fees[0]),
|
|
291
|
+
nonce: integer(nonce),
|
|
292
|
+
sender: sender as Address.Address,
|
|
293
|
+
signatures: signatures.map((entry) =>
|
|
294
|
+
FrameSignature.fromTuple(entry as FrameSignature.Tuple),
|
|
295
|
+
),
|
|
296
|
+
type,
|
|
297
|
+
}
|
|
298
|
+
if (wrapped) {
|
|
299
|
+
if (
|
|
300
|
+
decoded.length !== 5 ||
|
|
301
|
+
decoded[1] !== '0x01' ||
|
|
302
|
+
!Array.isArray(decoded[2]) ||
|
|
303
|
+
!Array.isArray(decoded[3]) ||
|
|
304
|
+
!Array.isArray(decoded[4])
|
|
305
|
+
)
|
|
306
|
+
throw new InvalidError('Expected a version 1 PeerDAS wrapper.')
|
|
307
|
+
envelope.sidecars = {
|
|
308
|
+
blobs: decoded[2] as Hex.Hex[],
|
|
309
|
+
cellProofs: decoded[4] as Hex.Hex[],
|
|
310
|
+
commitments: decoded[3] as Hex.Hex[],
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
assert(envelope)
|
|
314
|
+
// Re-encoding rejects nonminimal RLP lengths as well as malformed nested lists.
|
|
315
|
+
if (serialize(envelope).toLowerCase() !== serialized.toLowerCase())
|
|
316
|
+
throw new InvalidError('Noncanonical transaction encoding.')
|
|
317
|
+
return envelope
|
|
318
|
+
}
|
|
319
|
+
export declare namespace deserialize {
|
|
320
|
+
type ErrorType =
|
|
321
|
+
| assert.ErrorType
|
|
322
|
+
| Hex.slice.ErrorType
|
|
323
|
+
| Rlp.toHex.ErrorType
|
|
324
|
+
| serialize.ErrorType
|
|
325
|
+
| Errors.GlobalErrorType
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Creates an EIP-8141 transaction envelope from an object or serialized transaction.
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ### Basic Usage
|
|
333
|
+
*
|
|
334
|
+
* ```ts twoslash
|
|
335
|
+
* import { TxEnvelopeEip8141 } from 'ox'
|
|
336
|
+
*
|
|
337
|
+
* const envelope = TxEnvelopeEip8141.from({
|
|
338
|
+
* chainId: 1,
|
|
339
|
+
* frames: [
|
|
340
|
+
* {
|
|
341
|
+
* flags: 'approveExecutionAndPayment',
|
|
342
|
+
* gas: 50_000n,
|
|
343
|
+
* mode: 'verify'
|
|
344
|
+
* }
|
|
345
|
+
* ],
|
|
346
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
347
|
+
* })
|
|
348
|
+
* ```
|
|
349
|
+
*
|
|
350
|
+
* @param envelope - An envelope object or serialized transaction.
|
|
351
|
+
* @returns The envelope with its transaction type.
|
|
352
|
+
*/
|
|
353
|
+
export function from<
|
|
354
|
+
const envelope extends PartialBy<TxEnvelopeEip8141, 'type'> | Serialized,
|
|
355
|
+
>(envelope: envelope): from.ReturnType<envelope> {
|
|
356
|
+
const value = (
|
|
357
|
+
typeof envelope === 'string' ? deserialize(envelope) : envelope
|
|
358
|
+
) as PartialBy<TxEnvelopeEip8141, 'type'>
|
|
359
|
+
assert(value)
|
|
360
|
+
return { ...value, type } as from.ReturnType<envelope>
|
|
361
|
+
}
|
|
362
|
+
export declare namespace from {
|
|
363
|
+
type ReturnType<
|
|
364
|
+
envelope extends PartialBy<TxEnvelopeEip8141, 'type'> | Serialized,
|
|
365
|
+
> = envelope extends Serialized
|
|
366
|
+
? TxEnvelopeEip8141
|
|
367
|
+
: Compute<Assign<envelope, { readonly type: Type }>>
|
|
368
|
+
type ErrorType =
|
|
369
|
+
| assert.ErrorType
|
|
370
|
+
| deserialize.ErrorType
|
|
371
|
+
| Errors.GlobalErrorType
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Converts an RPC envelope to an EIP-8141 envelope without losing chain ID precision.
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* ### Basic Usage
|
|
379
|
+
*
|
|
380
|
+
* ```ts twoslash
|
|
381
|
+
* import { Frame, TxEnvelopeEip8141 } from 'ox'
|
|
382
|
+
*
|
|
383
|
+
* const rpc = TxEnvelopeEip8141.toRpc(
|
|
384
|
+
* TxEnvelopeEip8141.from({
|
|
385
|
+
* chainId: 1,
|
|
386
|
+
* frames: [Frame.from({})],
|
|
387
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
388
|
+
* })
|
|
389
|
+
* )
|
|
390
|
+
* const envelope = TxEnvelopeEip8141.fromRpc(rpc)
|
|
391
|
+
* ```
|
|
392
|
+
*
|
|
393
|
+
* @param envelope - The value to convert.
|
|
394
|
+
* @returns The converted value.
|
|
395
|
+
*/
|
|
396
|
+
export function fromRpc(envelope: Rpc): TxEnvelopeEip8141 {
|
|
397
|
+
const chainId = Hex.toBigInt(envelope.chainId)
|
|
398
|
+
return from({
|
|
399
|
+
blobVersionedHashes: envelope.blobVersionedHashes,
|
|
400
|
+
chainId:
|
|
401
|
+
chainId <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(chainId) : chainId,
|
|
402
|
+
frames: envelope.frames.map(Frame.fromRpc),
|
|
403
|
+
maxFeePerBlobGas: Hex.toBigInt(envelope.maxFeePerBlobGas),
|
|
404
|
+
maxFeePerGas: Hex.toBigInt(envelope.maxFeePerGas),
|
|
405
|
+
maxPriorityFeePerGas: Hex.toBigInt(envelope.maxPriorityFeePerGas),
|
|
406
|
+
nonce: Hex.toBigInt(envelope.nonce),
|
|
407
|
+
sender: envelope.from,
|
|
408
|
+
signatures: envelope.signatures.map(FrameSignature.fromRpc),
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export declare namespace fromRpc {
|
|
413
|
+
type ErrorType =
|
|
414
|
+
| from.ErrorType
|
|
415
|
+
| Frame.fromRpc.ErrorType
|
|
416
|
+
| FrameSignature.fromRpc.ErrorType
|
|
417
|
+
| Hex.toBigInt.ErrorType
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Converts an EIP-8141 envelope to RPC fields. Sidecars are excluded.
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* ### Basic Usage
|
|
425
|
+
*
|
|
426
|
+
* ```ts twoslash
|
|
427
|
+
* import { Frame, TxEnvelopeEip8141 } from 'ox'
|
|
428
|
+
*
|
|
429
|
+
* const envelope = TxEnvelopeEip8141.from({
|
|
430
|
+
* chainId: 1,
|
|
431
|
+
* frames: [Frame.from({})],
|
|
432
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
433
|
+
* })
|
|
434
|
+
* const rpc = TxEnvelopeEip8141.toRpc(envelope)
|
|
435
|
+
* ```
|
|
436
|
+
*
|
|
437
|
+
* @param envelope - The value to convert.
|
|
438
|
+
* @returns The converted value.
|
|
439
|
+
*/
|
|
440
|
+
export function toRpc(envelope: toRpc.Input): Rpc {
|
|
441
|
+
return {
|
|
442
|
+
blobVersionedHashes: envelope.blobVersionedHashes ?? [],
|
|
443
|
+
chainId: Quantity.fromNumberish(envelope.chainId),
|
|
444
|
+
frames: envelope.frames.map(Frame.toRpc),
|
|
445
|
+
from: envelope.sender,
|
|
446
|
+
maxFeePerBlobGas: Quantity.fromNumberish(envelope.maxFeePerBlobGas ?? 0n),
|
|
447
|
+
maxFeePerGas: Quantity.fromNumberish(envelope.maxFeePerGas ?? 0n),
|
|
448
|
+
maxPriorityFeePerGas: Quantity.fromNumberish(
|
|
449
|
+
envelope.maxPriorityFeePerGas ?? 0n,
|
|
450
|
+
),
|
|
451
|
+
nonce: Quantity.fromNumberish(envelope.nonce ?? 0n),
|
|
452
|
+
signatures: (envelope.signatures ?? []).map(FrameSignature.toRpc),
|
|
453
|
+
type: '0x6',
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export declare namespace toRpc {
|
|
458
|
+
type Input = Omit<
|
|
459
|
+
TxEnvelopeEip8141,
|
|
460
|
+
| 'chainId'
|
|
461
|
+
| 'frames'
|
|
462
|
+
| 'maxFeePerBlobGas'
|
|
463
|
+
| 'maxFeePerGas'
|
|
464
|
+
| 'maxPriorityFeePerGas'
|
|
465
|
+
| 'nonce'
|
|
466
|
+
| 'type'
|
|
467
|
+
> & {
|
|
468
|
+
chainId: Hex.Hex | bigint | number
|
|
469
|
+
frames: readonly Frame.toRpc.Input[]
|
|
470
|
+
maxFeePerBlobGas?: Hex.Hex | bigint | number | undefined
|
|
471
|
+
maxFeePerGas?: Hex.Hex | bigint | number | undefined
|
|
472
|
+
maxPriorityFeePerGas?: Hex.Hex | bigint | number | undefined
|
|
473
|
+
nonce?: Hex.Hex | bigint | number | undefined
|
|
474
|
+
type?: Type | undefined
|
|
475
|
+
}
|
|
476
|
+
type ErrorType =
|
|
477
|
+
| Frame.toRpc.ErrorType
|
|
478
|
+
| FrameSignature.toRpc.ErrorType
|
|
479
|
+
| Hex.fromNumber.ErrorType
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Returns the canonical signing payload of an EIP-8141 envelope.
|
|
484
|
+
*
|
|
485
|
+
* Elides signature bytes only for entries with an empty payload. Explicit-payload
|
|
486
|
+
* signatures remain committed. The envelope is not mutated.
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* ### Signing
|
|
490
|
+
*
|
|
491
|
+
* ```ts twoslash
|
|
492
|
+
* import {
|
|
493
|
+
* Address,
|
|
494
|
+
* FrameSignature,
|
|
495
|
+
* Secp256k1,
|
|
496
|
+
* TxEnvelopeEip8141
|
|
497
|
+
* } from 'ox'
|
|
498
|
+
*
|
|
499
|
+
* const privateKey = Secp256k1.randomPrivateKey()
|
|
500
|
+
* const sender = Address.fromPublicKey(
|
|
501
|
+
* Secp256k1.getPublicKey({ privateKey })
|
|
502
|
+
* )
|
|
503
|
+
* const envelope = TxEnvelopeEip8141.from({
|
|
504
|
+
* chainId: 1,
|
|
505
|
+
* frames: [
|
|
506
|
+
* {
|
|
507
|
+
* flags: 'approveExecutionAndPayment',
|
|
508
|
+
* gas: 50_000n,
|
|
509
|
+
* mode: 'verify'
|
|
510
|
+
* }
|
|
511
|
+
* ],
|
|
512
|
+
* sender,
|
|
513
|
+
* signatures: [FrameSignature.from({ scheme: 'secp256k1' })]
|
|
514
|
+
* })
|
|
515
|
+
*
|
|
516
|
+
* const payload = TxEnvelopeEip8141.getSignPayload(envelope)
|
|
517
|
+
* const signature = Secp256k1.sign({ payload, privateKey })
|
|
518
|
+
* const signed = TxEnvelopeEip8141.from({
|
|
519
|
+
* ...envelope,
|
|
520
|
+
* signatures: [
|
|
521
|
+
* FrameSignature.from({ scheme: 'secp256k1', signature })
|
|
522
|
+
* ]
|
|
523
|
+
* })
|
|
524
|
+
* ```
|
|
525
|
+
*
|
|
526
|
+
* @param envelope - The transaction envelope to sign.
|
|
527
|
+
* @returns The canonical signing digest.
|
|
528
|
+
*/
|
|
529
|
+
export function getSignPayload(
|
|
530
|
+
envelope: PartialBy<TxEnvelopeEip8141, 'type'>,
|
|
531
|
+
): Hex.Hex {
|
|
532
|
+
return hash(envelope, { presign: true })
|
|
533
|
+
}
|
|
534
|
+
export declare namespace getSignPayload {
|
|
535
|
+
type ErrorType = hash.ErrorType
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Hashes an EIP-8141 transaction, excluding its blob sidecars.
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ### Basic Usage
|
|
543
|
+
*
|
|
544
|
+
* ```ts twoslash
|
|
545
|
+
* import { Frame, TxEnvelopeEip8141 } from 'ox'
|
|
546
|
+
*
|
|
547
|
+
* const hash = TxEnvelopeEip8141.hash({
|
|
548
|
+
* chainId: 1,
|
|
549
|
+
* frames: [Frame.from({})],
|
|
550
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
551
|
+
* })
|
|
552
|
+
* ```
|
|
553
|
+
*
|
|
554
|
+
* @param envelope - The transaction envelope to hash.
|
|
555
|
+
* @param options - Hashing options.
|
|
556
|
+
* @returns The transaction hash or signing digest.
|
|
557
|
+
*/
|
|
558
|
+
export function hash(
|
|
559
|
+
envelope: PartialBy<TxEnvelopeEip8141, 'type'>,
|
|
560
|
+
options: hash.Options = {},
|
|
561
|
+
): Hex.Hex {
|
|
562
|
+
assert(envelope)
|
|
563
|
+
const body = toTuple(envelope)
|
|
564
|
+
if (options.presign)
|
|
565
|
+
body[4] = body[4].map((entry) =>
|
|
566
|
+
entry[2] === '0x' ? [entry[0], entry[1], entry[2], '0x'] : entry,
|
|
567
|
+
)
|
|
568
|
+
return Hash.keccak256(Hex.concat(serializedType, Rlp.fromHex(body)))
|
|
569
|
+
}
|
|
570
|
+
export declare namespace hash {
|
|
571
|
+
type Options = {
|
|
572
|
+
/** Whether to compute the canonical signing digest. @default false */
|
|
573
|
+
presign?: boolean | undefined
|
|
574
|
+
}
|
|
575
|
+
type ErrorType =
|
|
576
|
+
| assert.ErrorType
|
|
577
|
+
| Hash.keccak256.ErrorType
|
|
578
|
+
| Rlp.fromHex.ErrorType
|
|
579
|
+
| Errors.GlobalErrorType
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Serializes an EIP-8141 envelope, including a PeerDAS wrapper when sidecars exist.
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ### Basic Usage
|
|
587
|
+
*
|
|
588
|
+
* ```ts twoslash
|
|
589
|
+
* import { TxEnvelopeEip8141 } from 'ox'
|
|
590
|
+
*
|
|
591
|
+
* const envelope = TxEnvelopeEip8141.from({
|
|
592
|
+
* chainId: 1,
|
|
593
|
+
* frames: [{ gas: 50_000n, mode: 'sender' }],
|
|
594
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
595
|
+
* })
|
|
596
|
+
* const serialized = TxEnvelopeEip8141.serialize(envelope)
|
|
597
|
+
* ```
|
|
598
|
+
*
|
|
599
|
+
* @param envelope - The transaction envelope to serialize.
|
|
600
|
+
* @returns The serialized transaction.
|
|
601
|
+
*/
|
|
602
|
+
export function serialize(
|
|
603
|
+
envelope: PartialBy<TxEnvelopeEip8141, 'type'>,
|
|
604
|
+
): Serialized {
|
|
605
|
+
assert(envelope)
|
|
606
|
+
const body = toTuple(envelope)
|
|
607
|
+
const { sidecars } = envelope
|
|
608
|
+
if (sidecars) {
|
|
609
|
+
const { blobs, cellProofs, commitments } = sidecars
|
|
610
|
+
const hashes = envelope.blobVersionedHashes ?? []
|
|
611
|
+
if (
|
|
612
|
+
hashes.length === 0 ||
|
|
613
|
+
blobs.length !== hashes.length ||
|
|
614
|
+
commitments.length !== hashes.length ||
|
|
615
|
+
cellProofs.length !== hashes.length * 128
|
|
616
|
+
)
|
|
617
|
+
throw new InvalidError('PeerDAS sidecar counts do not match blob hashes.')
|
|
618
|
+
for (const [index, blob] of blobs.entries()) {
|
|
619
|
+
Hex.assert(blob, { strict: true })
|
|
620
|
+
const commitment = commitments[index]!
|
|
621
|
+
Hex.assert(commitment, { strict: true })
|
|
622
|
+
if (
|
|
623
|
+
blob.length !== 2 + Blobs.bytesPerBlob * 2 ||
|
|
624
|
+
commitment.length !== 98 ||
|
|
625
|
+
Blobs.commitmentToVersionedHash(commitment).toLowerCase() !==
|
|
626
|
+
hashes[index]!.toLowerCase()
|
|
627
|
+
)
|
|
628
|
+
throw new InvalidError('Invalid blob size or commitment.')
|
|
629
|
+
}
|
|
630
|
+
for (const proof of cellProofs) {
|
|
631
|
+
Hex.assert(proof, { strict: true })
|
|
632
|
+
if (proof.length !== 98)
|
|
633
|
+
throw new InvalidError('Cell proofs must contain 48 bytes.')
|
|
634
|
+
}
|
|
635
|
+
return Hex.concat(
|
|
636
|
+
serializedType,
|
|
637
|
+
Rlp.fromHex([body, '0x01', blobs, commitments, cellProofs]),
|
|
638
|
+
) as Serialized
|
|
639
|
+
}
|
|
640
|
+
return Hex.concat(serializedType, Rlp.fromHex(body)) as Serialized
|
|
641
|
+
}
|
|
642
|
+
export declare namespace serialize {
|
|
643
|
+
type ErrorType =
|
|
644
|
+
| assert.ErrorType
|
|
645
|
+
| Rlp.fromHex.ErrorType
|
|
646
|
+
| Hex.concat.ErrorType
|
|
647
|
+
| Errors.GlobalErrorType
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Returns whether an EIP-8141 envelope satisfies structural constraints.
|
|
652
|
+
*
|
|
653
|
+
* @example
|
|
654
|
+
* ### Basic Usage
|
|
655
|
+
*
|
|
656
|
+
* ```ts twoslash
|
|
657
|
+
* import { Frame, TxEnvelopeEip8141 } from 'ox'
|
|
658
|
+
*
|
|
659
|
+
* const valid = TxEnvelopeEip8141.validate({
|
|
660
|
+
* chainId: 1,
|
|
661
|
+
* frames: [Frame.from({})],
|
|
662
|
+
* sender: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
|
|
663
|
+
* })
|
|
664
|
+
* ```
|
|
665
|
+
*
|
|
666
|
+
* @param envelope - The transaction envelope to validate.
|
|
667
|
+
* @returns Whether the envelope is structurally valid.
|
|
668
|
+
*/
|
|
669
|
+
export function validate(
|
|
670
|
+
envelope: PartialBy<TxEnvelopeEip8141, 'type'>,
|
|
671
|
+
): boolean {
|
|
672
|
+
try {
|
|
673
|
+
assert(envelope)
|
|
674
|
+
return true
|
|
675
|
+
} catch {
|
|
676
|
+
return false
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
export declare namespace validate {
|
|
680
|
+
type ErrorType = Errors.GlobalErrorType
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/** Thrown when an EIP-8141 envelope is structurally invalid. */
|
|
684
|
+
export class InvalidError extends Errors.BaseError {
|
|
685
|
+
override readonly name = 'TxEnvelopeEip8141.InvalidError'
|
|
686
|
+
constructor(reason: string) {
|
|
687
|
+
super(reason)
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function toTuple(envelope: PartialBy<TxEnvelopeEip8141, 'type'>) {
|
|
692
|
+
const quantity = (value: bigint | number | undefined): Hex.Hex =>
|
|
693
|
+
value ? Hex.fromBytes(Bytes.fromNumber(value)) : '0x'
|
|
694
|
+
return [
|
|
695
|
+
quantity(envelope.chainId),
|
|
696
|
+
quantity(envelope.nonce),
|
|
697
|
+
envelope.sender,
|
|
698
|
+
envelope.frames.map((frame) => Frame.toTuple(frame)),
|
|
699
|
+
(envelope.signatures ?? []).map((entry) => FrameSignature.toTuple(entry)),
|
|
700
|
+
[
|
|
701
|
+
quantity(envelope.maxPriorityFeePerGas),
|
|
702
|
+
quantity(envelope.maxFeePerGas),
|
|
703
|
+
quantity(envelope.maxFeePerBlobGas),
|
|
704
|
+
],
|
|
705
|
+
envelope.blobVersionedHashes ?? [],
|
|
706
|
+
] satisfies [
|
|
707
|
+
Hex.Hex,
|
|
708
|
+
Hex.Hex,
|
|
709
|
+
Address.Address,
|
|
710
|
+
Frame.Tuple[],
|
|
711
|
+
FrameSignature.Tuple[],
|
|
712
|
+
Hex.Hex[],
|
|
713
|
+
readonly Hex.Hex[],
|
|
714
|
+
]
|
|
715
|
+
}
|