ox 0.9.16 → 0.10.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.
Files changed (216) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +4 -4
  3. package/TxEnvelope/package.json +6 -0
  4. package/TxEnvelopeEip1559/package.json +6 -0
  5. package/TxEnvelopeEip2930/package.json +6 -0
  6. package/TxEnvelopeEip4844/package.json +6 -0
  7. package/TxEnvelopeEip7702/package.json +6 -0
  8. package/TxEnvelopeLegacy/package.json +6 -0
  9. package/_cjs/core/{TransactionEnvelope.js → TxEnvelope.js} +1 -1
  10. package/_cjs/core/TxEnvelope.js.map +1 -0
  11. package/_cjs/core/{TransactionEnvelopeEip1559.js → TxEnvelopeEip1559.js} +2 -2
  12. package/_cjs/core/TxEnvelopeEip1559.js.map +1 -0
  13. package/_cjs/core/{TransactionEnvelopeEip2930.js → TxEnvelopeEip2930.js} +2 -2
  14. package/_cjs/core/TxEnvelopeEip2930.js.map +1 -0
  15. package/_cjs/core/{TransactionEnvelopeEip4844.js → TxEnvelopeEip4844.js} +4 -4
  16. package/_cjs/core/TxEnvelopeEip4844.js.map +1 -0
  17. package/_cjs/core/{TransactionEnvelopeEip7702.js → TxEnvelopeEip7702.js} +4 -4
  18. package/_cjs/core/TxEnvelopeEip7702.js.map +1 -0
  19. package/_cjs/core/{TransactionEnvelopeLegacy.js → TxEnvelopeLegacy.js} +2 -2
  20. package/_cjs/core/TxEnvelopeLegacy.js.map +1 -0
  21. package/_cjs/core/WebAuthnP256.js +1 -1
  22. package/_cjs/core/WebAuthnP256.js.map +1 -1
  23. package/_cjs/erc8021/Attribution.js +36 -6
  24. package/_cjs/erc8021/Attribution.js.map +1 -1
  25. package/_cjs/index.docs.js +1 -0
  26. package/_cjs/index.docs.js.map +1 -1
  27. package/_cjs/index.js +7 -7
  28. package/_cjs/index.js.map +1 -1
  29. package/_cjs/tempo/AuthorizationTempo.js +101 -0
  30. package/_cjs/tempo/AuthorizationTempo.js.map +1 -0
  31. package/_cjs/tempo/KeyAuthorization.js +123 -0
  32. package/_cjs/tempo/KeyAuthorization.js.map +1 -0
  33. package/_cjs/tempo/PoolId.js +10 -0
  34. package/_cjs/tempo/PoolId.js.map +1 -0
  35. package/_cjs/tempo/SignatureEnvelope.js +394 -0
  36. package/_cjs/tempo/SignatureEnvelope.js.map +1 -0
  37. package/_cjs/tempo/Tick.js +77 -0
  38. package/_cjs/tempo/Tick.js.map +1 -0
  39. package/_cjs/tempo/TokenId.js +28 -0
  40. package/_cjs/tempo/TokenId.js.map +1 -0
  41. package/_cjs/tempo/TokenRole.js +26 -0
  42. package/_cjs/tempo/TokenRole.js.map +1 -0
  43. package/_cjs/tempo/Transaction.js +80 -0
  44. package/_cjs/tempo/Transaction.js.map +1 -0
  45. package/_cjs/tempo/TransactionReceipt.js +26 -0
  46. package/_cjs/tempo/TransactionReceipt.js.map +1 -0
  47. package/_cjs/tempo/TransactionRequest.js +53 -0
  48. package/_cjs/tempo/TransactionRequest.js.map +1 -0
  49. package/_cjs/tempo/TxEnvelopeTempo.js +267 -0
  50. package/_cjs/tempo/TxEnvelopeTempo.js.map +1 -0
  51. package/_cjs/tempo/index.js +15 -0
  52. package/_cjs/tempo/index.js.map +1 -0
  53. package/_cjs/version.js +1 -1
  54. package/_esm/core/Blobs.js +8 -8
  55. package/_esm/core/{TransactionEnvelope.js → TxEnvelope.js} +11 -11
  56. package/_esm/core/TxEnvelope.js.map +1 -0
  57. package/_esm/core/{TransactionEnvelopeEip1559.js → TxEnvelopeEip1559.js} +42 -42
  58. package/_esm/core/TxEnvelopeEip1559.js.map +1 -0
  59. package/_esm/core/{TransactionEnvelopeEip2930.js → TxEnvelopeEip2930.js} +43 -43
  60. package/_esm/core/TxEnvelopeEip2930.js.map +1 -0
  61. package/_esm/core/{TransactionEnvelopeEip4844.js → TxEnvelopeEip4844.js} +42 -42
  62. package/_esm/core/TxEnvelopeEip4844.js.map +1 -0
  63. package/_esm/core/{TransactionEnvelopeEip7702.js → TxEnvelopeEip7702.js} +40 -40
  64. package/_esm/core/TxEnvelopeEip7702.js.map +1 -0
  65. package/_esm/core/{TransactionEnvelopeLegacy.js → TxEnvelopeLegacy.js} +42 -42
  66. package/_esm/core/TxEnvelopeLegacy.js.map +1 -0
  67. package/_esm/core/WebAuthnP256.js +1 -1
  68. package/_esm/core/WebAuthnP256.js.map +1 -1
  69. package/_esm/erc8021/Attribution.js +58 -13
  70. package/_esm/erc8021/Attribution.js.map +1 -1
  71. package/_esm/index.docs.js +1 -0
  72. package/_esm/index.docs.js.map +1 -1
  73. package/_esm/index.js +192 -192
  74. package/_esm/index.js.map +1 -1
  75. package/_esm/tempo/AuthorizationTempo.js +664 -0
  76. package/_esm/tempo/AuthorizationTempo.js.map +1 -0
  77. package/_esm/tempo/KeyAuthorization.js +426 -0
  78. package/_esm/tempo/KeyAuthorization.js.map +1 -0
  79. package/_esm/tempo/PoolId.js +28 -0
  80. package/_esm/tempo/PoolId.js.map +1 -0
  81. package/_esm/tempo/SignatureEnvelope.js +660 -0
  82. package/_esm/tempo/SignatureEnvelope.js.map +1 -0
  83. package/_esm/tempo/Tick.js +147 -0
  84. package/_esm/tempo/Tick.js.map +1 -0
  85. package/_esm/tempo/TokenId.js +71 -0
  86. package/_esm/tempo/TokenId.js.map +1 -0
  87. package/_esm/tempo/TokenRole.js +40 -0
  88. package/_esm/tempo/TokenRole.js.map +1 -0
  89. package/_esm/tempo/Transaction.js +167 -0
  90. package/_esm/tempo/Transaction.js.map +1 -0
  91. package/_esm/tempo/TransactionReceipt.js +138 -0
  92. package/_esm/tempo/TransactionReceipt.js.map +1 -0
  93. package/_esm/tempo/TransactionRequest.js +99 -0
  94. package/_esm/tempo/TransactionRequest.js.map +1 -0
  95. package/_esm/tempo/TxEnvelopeTempo.js +607 -0
  96. package/_esm/tempo/TxEnvelopeTempo.js.map +1 -0
  97. package/_esm/tempo/index.js +298 -0
  98. package/_esm/tempo/index.js.map +1 -0
  99. package/_esm/version.js +1 -1
  100. package/_types/core/Blobs.d.ts +8 -8
  101. package/_types/core/{TransactionEnvelope.d.ts → TxEnvelope.d.ts} +11 -11
  102. package/_types/core/TxEnvelope.d.ts.map +1 -0
  103. package/_types/core/{TransactionEnvelopeEip1559.d.ts → TxEnvelopeEip1559.d.ts} +54 -54
  104. package/_types/core/TxEnvelopeEip1559.d.ts.map +1 -0
  105. package/_types/core/{TransactionEnvelopeEip2930.d.ts → TxEnvelopeEip2930.d.ts} +55 -55
  106. package/_types/core/TxEnvelopeEip2930.d.ts.map +1 -0
  107. package/_types/core/{TransactionEnvelopeEip4844.d.ts → TxEnvelopeEip4844.d.ts} +54 -54
  108. package/_types/core/TxEnvelopeEip4844.d.ts.map +1 -0
  109. package/_types/core/{TransactionEnvelopeEip7702.d.ts → TxEnvelopeEip7702.d.ts} +49 -49
  110. package/_types/core/TxEnvelopeEip7702.d.ts.map +1 -0
  111. package/_types/core/{TransactionEnvelopeLegacy.d.ts → TxEnvelopeLegacy.d.ts} +54 -54
  112. package/_types/core/TxEnvelopeLegacy.d.ts.map +1 -0
  113. package/_types/core/WebAuthnP256.d.ts +1 -1
  114. package/_types/core/WebAuthnP256.d.ts.map +1 -1
  115. package/_types/erc8021/Attribution.d.ts +20 -6
  116. package/_types/erc8021/Attribution.d.ts.map +1 -1
  117. package/_types/index.d.ts +192 -192
  118. package/_types/index.d.ts.map +1 -1
  119. package/_types/index.docs.d.ts +1 -0
  120. package/_types/index.docs.d.ts.map +1 -1
  121. package/_types/tempo/AuthorizationTempo.d.ts +688 -0
  122. package/_types/tempo/AuthorizationTempo.d.ts.map +1 -0
  123. package/_types/tempo/KeyAuthorization.d.ts +437 -0
  124. package/_types/tempo/KeyAuthorization.d.ts.map +1 -0
  125. package/_types/tempo/PoolId.d.ts +33 -0
  126. package/_types/tempo/PoolId.d.ts.map +1 -0
  127. package/_types/tempo/SignatureEnvelope.d.ts +438 -0
  128. package/_types/tempo/SignatureEnvelope.d.ts.map +1 -0
  129. package/_types/tempo/Tick.d.ts +120 -0
  130. package/_types/tempo/Tick.d.ts.map +1 -0
  131. package/_types/tempo/TokenId.d.ts +55 -0
  132. package/_types/tempo/TokenId.d.ts.map +1 -0
  133. package/_types/tempo/TokenRole.d.ts +29 -0
  134. package/_types/tempo/TokenRole.d.ts.map +1 -0
  135. package/_types/tempo/Transaction.d.ts +208 -0
  136. package/_types/tempo/Transaction.d.ts.map +1 -0
  137. package/_types/tempo/TransactionReceipt.d.ts +165 -0
  138. package/_types/tempo/TransactionReceipt.d.ts.map +1 -0
  139. package/_types/tempo/TransactionRequest.d.ts +89 -0
  140. package/_types/tempo/TransactionRequest.d.ts.map +1 -0
  141. package/_types/tempo/TxEnvelopeTempo.d.ts +551 -0
  142. package/_types/tempo/TxEnvelopeTempo.d.ts.map +1 -0
  143. package/_types/tempo/index.d.ts +300 -0
  144. package/_types/tempo/index.d.ts.map +1 -0
  145. package/_types/version.d.ts +1 -1
  146. package/core/Blobs.ts +8 -8
  147. package/core/{TransactionEnvelope.ts → TxEnvelope.ts} +10 -10
  148. package/core/{TransactionEnvelopeEip1559.ts → TxEnvelopeEip1559.ts} +60 -69
  149. package/core/{TransactionEnvelopeEip2930.ts → TxEnvelopeEip2930.ts} +61 -72
  150. package/core/{TransactionEnvelopeEip4844.ts → TxEnvelopeEip4844.ts} +62 -71
  151. package/core/{TransactionEnvelopeEip7702.ts → TxEnvelopeEip7702.ts} +58 -67
  152. package/core/{TransactionEnvelopeLegacy.ts → TxEnvelopeLegacy.ts} +59 -68
  153. package/core/WebAuthnP256.ts +3 -1
  154. package/erc8021/Attribution.ts +77 -15
  155. package/index.docs.ts +1 -0
  156. package/index.ts +192 -195
  157. package/package.json +91 -31
  158. package/tempo/AuthorizationTempo/package.json +6 -0
  159. package/tempo/AuthorizationTempo.test.ts +1293 -0
  160. package/tempo/AuthorizationTempo.ts +884 -0
  161. package/tempo/KeyAuthorization/package.json +6 -0
  162. package/tempo/KeyAuthorization.test.ts +1373 -0
  163. package/tempo/KeyAuthorization.ts +622 -0
  164. package/tempo/PoolId/package.json +6 -0
  165. package/tempo/PoolId.test.ts +33 -0
  166. package/tempo/PoolId.ts +42 -0
  167. package/tempo/SignatureEnvelope/package.json +6 -0
  168. package/tempo/SignatureEnvelope.test.ts +1877 -0
  169. package/tempo/SignatureEnvelope.ts +973 -0
  170. package/tempo/Tick/package.json +6 -0
  171. package/tempo/Tick.test.ts +281 -0
  172. package/tempo/Tick.ts +186 -0
  173. package/tempo/TokenId/package.json +6 -0
  174. package/tempo/TokenId.test.ts +40 -0
  175. package/tempo/TokenId.ts +80 -0
  176. package/tempo/TokenRole/package.json +6 -0
  177. package/tempo/TokenRole.test.ts +16 -0
  178. package/tempo/TokenRole.ts +45 -0
  179. package/tempo/Transaction/package.json +6 -0
  180. package/tempo/Transaction.test.ts +523 -0
  181. package/tempo/Transaction.ts +339 -0
  182. package/tempo/TransactionReceipt/package.json +6 -0
  183. package/tempo/TransactionReceipt.ts +200 -0
  184. package/tempo/TransactionRequest/package.json +6 -0
  185. package/tempo/TransactionRequest.ts +160 -0
  186. package/tempo/TxEnvelopeTempo/package.json +6 -0
  187. package/tempo/TxEnvelopeTempo.test.ts +1371 -0
  188. package/tempo/TxEnvelopeTempo.ts +972 -0
  189. package/tempo/e2e.test.ts +1387 -0
  190. package/tempo/index.ts +308 -0
  191. package/tempo/package.json +6 -0
  192. package/version.ts +1 -1
  193. package/TransactionEnvelope/package.json +0 -6
  194. package/TransactionEnvelopeEip1559/package.json +0 -6
  195. package/TransactionEnvelopeEip2930/package.json +0 -6
  196. package/TransactionEnvelopeEip4844/package.json +0 -6
  197. package/TransactionEnvelopeEip7702/package.json +0 -6
  198. package/TransactionEnvelopeLegacy/package.json +0 -6
  199. package/_cjs/core/TransactionEnvelope.js.map +0 -1
  200. package/_cjs/core/TransactionEnvelopeEip1559.js.map +0 -1
  201. package/_cjs/core/TransactionEnvelopeEip2930.js.map +0 -1
  202. package/_cjs/core/TransactionEnvelopeEip4844.js.map +0 -1
  203. package/_cjs/core/TransactionEnvelopeEip7702.js.map +0 -1
  204. package/_cjs/core/TransactionEnvelopeLegacy.js.map +0 -1
  205. package/_esm/core/TransactionEnvelope.js.map +0 -1
  206. package/_esm/core/TransactionEnvelopeEip1559.js.map +0 -1
  207. package/_esm/core/TransactionEnvelopeEip2930.js.map +0 -1
  208. package/_esm/core/TransactionEnvelopeEip4844.js.map +0 -1
  209. package/_esm/core/TransactionEnvelopeEip7702.js.map +0 -1
  210. package/_esm/core/TransactionEnvelopeLegacy.js.map +0 -1
  211. package/_types/core/TransactionEnvelope.d.ts.map +0 -1
  212. package/_types/core/TransactionEnvelopeEip1559.d.ts.map +0 -1
  213. package/_types/core/TransactionEnvelopeEip2930.d.ts.map +0 -1
  214. package/_types/core/TransactionEnvelopeEip4844.d.ts.map +0 -1
  215. package/_types/core/TransactionEnvelopeEip7702.d.ts.map +0 -1
  216. package/_types/core/TransactionEnvelopeLegacy.d.ts.map +0 -1
@@ -0,0 +1,972 @@
1
+ import * as AccessList from '../core/AccessList.js'
2
+ import * as Address from '../core/Address.js'
3
+ import * as Errors from '../core/Errors.js'
4
+ import * as Hash from '../core/Hash.js'
5
+ import * as Hex from '../core/Hex.js'
6
+ import type {
7
+ Assign,
8
+ Compute,
9
+ OneOf,
10
+ PartialBy,
11
+ UnionPartialBy,
12
+ } from '../core/internal/types.js'
13
+ import * as Rlp from '../core/Rlp.js'
14
+ import * as Signature from '../core/Signature.js'
15
+ import * as TransactionEnvelope from '../core/TxEnvelope.js'
16
+ import * as AuthorizationTempo from './AuthorizationTempo.js'
17
+ import * as KeyAuthorization from './KeyAuthorization.js'
18
+ import * as SignatureEnvelope from './SignatureEnvelope.js'
19
+ import * as TokenId from './TokenId.js'
20
+
21
+ /**
22
+ * Represents a single call within a Tempo transaction.
23
+ *
24
+ * Tempo transactions support batching multiple calls for atomic execution.
25
+ *
26
+ * [Batch Calls](https://docs.tempo.xyz/protocol/transactions#batch-calls)
27
+ */
28
+ export type Call<bigintType = bigint> = {
29
+ /** Call data. */
30
+ data?: Hex.Hex | undefined
31
+ /** The target address or contract creation. */
32
+ to?: Address.Address | undefined
33
+ /** Value to send (in wei). */
34
+ value?: bigintType | undefined
35
+ }
36
+
37
+ /**
38
+ * Tempo transaction envelope (type `0x76`).
39
+ *
40
+ * A new EIP-2718 transaction type exclusively available on Tempo, designed for payment
41
+ * use cases with the following features:
42
+ *
43
+ * - **Configurable Fee Tokens**: Pay transaction fees with any USD-denominated TIP-20 token.
44
+ * The Fee AMM automatically converts to the validator's preferred token.
45
+ *
46
+ * - **Fee Sponsorship**: A third-party fee payer can pay fees on behalf of the sender using
47
+ * a dual-signature scheme (sender signs tx, fee payer signs over tx + sender address).
48
+ *
49
+ * - **Batch Calls**: Execute multiple operations atomically in a single transaction via
50
+ * the `calls` array, reducing overhead and simplifying wallet management.
51
+ *
52
+ * - **Access Keys**: Delegate signing to secondary keys with expiry and per-TIP-20 spending
53
+ * limits via `keyAuthorization`. Enables passkey UX without repeated prompts.
54
+ *
55
+ * - **Parallelizable Nonces**: Use different `nonceKey` values to submit multiple transactions
56
+ * in parallel without waiting for sequential nonce confirmation.
57
+ *
58
+ * - **Scheduled Transactions**: Set `validAfter` and `validBefore` timestamps to define a
59
+ * time window for when the transaction can be included in a block.
60
+ *
61
+ * - **Multi-Signature Support**: Sign with secp256k1, P256 (passkeys), or WebAuthn credentials.
62
+ *
63
+ * [Tempo Transaction Specification](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction)
64
+ */
65
+ export type TxEnvelopeTempo<
66
+ signed extends boolean = boolean,
67
+ bigintType = bigint,
68
+ numberType = number,
69
+ type extends string = Type,
70
+ > = Compute<
71
+ {
72
+ /** EIP-2930 Access List. */
73
+ accessList?: AccessList.AccessList | undefined
74
+ /** EIP-7702 (Tempo) Authorization list for the transaction. */
75
+ authorizationList?:
76
+ | AuthorizationTempo.ListSigned<bigintType, numberType>
77
+ | undefined
78
+ /** Array of calls to execute. */
79
+ calls: readonly Call<bigintType>[]
80
+ /** EIP-155 Chain ID. */
81
+ chainId: numberType
82
+ /** Sender of the transaction. */
83
+ from?: Address.Address | undefined
84
+ /** Gas provided for transaction execution */
85
+ gas?: bigintType | undefined
86
+ /** Fee payer signature. */
87
+ feePayerSignature?:
88
+ | Signature.Signature<true, bigintType, numberType>
89
+ | null
90
+ | undefined
91
+ /** Fee token preference. Address or ID of the TIP-20 token. */
92
+ feeToken?: TokenId.TokenIdOrAddress | undefined
93
+ /**
94
+ * Key authorization for provisioning a new access key.
95
+ *
96
+ * When present, this transaction will add the specified key to the AccountKeychain precompile,
97
+ * before verifying the transaction signature.
98
+ * The authorization must be signed with the root key, the tx can be signed by the Keychain signature.
99
+ */
100
+ keyAuthorization?:
101
+ | KeyAuthorization.Signed<bigintType, numberType>
102
+ | undefined
103
+ /** Total fee per gas in wei (gasPrice/baseFeePerGas + maxPriorityFeePerGas). */
104
+ maxFeePerGas?: bigintType | undefined
105
+ /** Max priority fee per gas (in wei). */
106
+ maxPriorityFeePerGas?: bigintType | undefined
107
+ /** Nonce key for 2D nonce system (192 bits). */
108
+ nonceKey?: bigintType | undefined
109
+ /** Unique number identifying this transaction */
110
+ nonce?: bigintType | undefined
111
+ /** Transaction type */
112
+ type: type
113
+ /** Transaction can only be included in a block before this timestamp. */
114
+ validBefore?: numberType | undefined
115
+ /** Transaction can only be included in a block after this timestamp. */
116
+ validAfter?: numberType | undefined
117
+ } & (signed extends true
118
+ ? {
119
+ signature: SignatureEnvelope.SignatureEnvelope<bigintType, numberType>
120
+ }
121
+ : {
122
+ signature?:
123
+ | SignatureEnvelope.SignatureEnvelope<bigintType, numberType>
124
+ | undefined
125
+ })
126
+ >
127
+
128
+ export type Rpc<signed extends boolean = boolean> = TxEnvelopeTempo<
129
+ signed,
130
+ Hex.Hex,
131
+ Hex.Hex,
132
+ '0x76'
133
+ >
134
+
135
+ export const feePayerMagic = '0x78' as const
136
+ export type FeePayerMagic = typeof feePayerMagic
137
+
138
+ export type Serialized = `${SerializedType}${string}`
139
+
140
+ export type Signed = TxEnvelopeTempo<true>
141
+
142
+ export const serializedType = '0x76' as const
143
+ export type SerializedType = typeof serializedType
144
+
145
+ export const type = 'tempo' as const
146
+ export type Type = typeof type
147
+
148
+ /**
149
+ * Asserts a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo} is valid.
150
+ *
151
+ * @example
152
+ * ```ts twoslash
153
+ * import { TxEnvelopeTempo } from 'ox/tempo'
154
+ *
155
+ * TxEnvelopeTempo.assert({
156
+ * calls: [{ to: '0x0000000000000000000000000000000000000000', value: 0n }],
157
+ * chainId: 1,
158
+ * maxFeePerGas: 1000000000n,
159
+ * })
160
+ * ```
161
+ *
162
+ * @param envelope - The transaction envelope to assert.
163
+ */
164
+ export function assert(envelope: PartialBy<TxEnvelopeTempo, 'type'>) {
165
+ const {
166
+ calls,
167
+ chainId,
168
+ maxFeePerGas,
169
+ maxPriorityFeePerGas,
170
+ validBefore,
171
+ validAfter,
172
+ } = envelope
173
+
174
+ // Calls must not be empty
175
+ if (!calls || calls.length === 0) throw new CallsEmptyError()
176
+
177
+ // validBefore must be greater than validAfter if both are set
178
+ if (
179
+ typeof validBefore === 'number' &&
180
+ typeof validAfter === 'number' &&
181
+ validBefore <= validAfter
182
+ ) {
183
+ throw new InvalidValidityWindowError({
184
+ validBefore: validBefore,
185
+ validAfter: validAfter,
186
+ })
187
+ }
188
+
189
+ // Validate each call
190
+ if (calls)
191
+ for (const call of calls)
192
+ if (call.to) Address.assert(call.to, { strict: false })
193
+
194
+ // Validate chain ID
195
+ if (chainId <= 0)
196
+ throw new TransactionEnvelope.InvalidChainIdError({ chainId })
197
+
198
+ // Validate max fee per gas
199
+ if (maxFeePerGas && BigInt(maxFeePerGas) > 2n ** 256n - 1n)
200
+ throw new TransactionEnvelope.FeeCapTooHighError({
201
+ feeCap: maxFeePerGas,
202
+ })
203
+
204
+ if (
205
+ maxPriorityFeePerGas &&
206
+ maxFeePerGas &&
207
+ maxPriorityFeePerGas > maxFeePerGas
208
+ )
209
+ throw new TransactionEnvelope.TipAboveFeeCapError({
210
+ maxFeePerGas,
211
+ maxPriorityFeePerGas,
212
+ })
213
+ }
214
+
215
+ export declare namespace assert {
216
+ type ErrorType =
217
+ | Address.assert.ErrorType
218
+ | CallsEmptyError
219
+ | InvalidValidityWindowError
220
+ | Errors.GlobalErrorType
221
+ }
222
+
223
+ /**
224
+ * Deserializes a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo} from its serialized form.
225
+ *
226
+ * @example
227
+ * ```ts twoslash
228
+ * import { TxEnvelopeTempo } from 'ox/tempo'
229
+ *
230
+ * const envelope = TxEnvelopeTempo.deserialize('0x76f84a0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0808080')
231
+ * // @log: {
232
+ * // @log: type: 'tempo',
233
+ * // @log: nonce: 785n,
234
+ * // @log: maxFeePerGas: 2000000000n,
235
+ * // @log: gas: 1000000n,
236
+ * // @log: calls: [{ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', value: 1000000000000000000n }],
237
+ * // @log: }
238
+ * ```
239
+ *
240
+ * @param serialized - The serialized transaction.
241
+ * @returns Deserialized Transaction Envelope.
242
+ */
243
+ export function deserialize(serialized: Serialized): Compute<TxEnvelopeTempo> {
244
+ const transactionArray = Rlp.toHex(Hex.slice(serialized, 1))
245
+
246
+ const [
247
+ chainId,
248
+ maxPriorityFeePerGas,
249
+ maxFeePerGas,
250
+ gas,
251
+ calls,
252
+ accessList,
253
+ nonceKey,
254
+ nonce,
255
+ validBefore,
256
+ validAfter,
257
+ feeToken,
258
+ feePayerSignatureOrSender,
259
+ authorizationList,
260
+ keyAuthorizationOrSignature,
261
+ maybeSignature,
262
+ ] = transactionArray as readonly Hex.Hex[]
263
+
264
+ const keyAuthorization = Array.isArray(keyAuthorizationOrSignature)
265
+ ? keyAuthorizationOrSignature
266
+ : undefined
267
+ const signature = keyAuthorization
268
+ ? maybeSignature
269
+ : keyAuthorizationOrSignature
270
+
271
+ if (
272
+ !(
273
+ transactionArray.length === 13 ||
274
+ transactionArray.length === 14 ||
275
+ transactionArray.length === 15
276
+ )
277
+ )
278
+ throw new TransactionEnvelope.InvalidSerializedError({
279
+ attributes: {
280
+ authorizationList,
281
+ chainId,
282
+ maxPriorityFeePerGas,
283
+ maxFeePerGas,
284
+ gas,
285
+ calls,
286
+ accessList,
287
+ keyAuthorization,
288
+ nonceKey,
289
+ nonce,
290
+ validBefore,
291
+ validAfter,
292
+ feeToken,
293
+ feePayerSignatureOrSender,
294
+ ...(transactionArray.length > 12
295
+ ? {
296
+ signature,
297
+ }
298
+ : {}),
299
+ },
300
+ serialized,
301
+ type,
302
+ })
303
+
304
+ let transaction = {
305
+ chainId: Number(chainId),
306
+ type,
307
+ } as TxEnvelopeTempo
308
+
309
+ if (Hex.validate(gas) && gas !== '0x') transaction.gas = BigInt(gas)
310
+ if (Hex.validate(nonce))
311
+ transaction.nonce = nonce === '0x' ? 0n : BigInt(nonce)
312
+ if (Hex.validate(maxFeePerGas) && maxFeePerGas !== '0x')
313
+ transaction.maxFeePerGas = BigInt(maxFeePerGas)
314
+ if (Hex.validate(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x')
315
+ transaction.maxPriorityFeePerGas = BigInt(maxPriorityFeePerGas)
316
+ if (Hex.validate(nonceKey))
317
+ transaction.nonceKey = nonceKey === '0x' ? 0n : BigInt(nonceKey)
318
+ if (Hex.validate(validBefore) && validBefore !== '0x')
319
+ transaction.validBefore = Number(validBefore)
320
+ if (Hex.validate(validAfter) && validAfter !== '0x')
321
+ transaction.validAfter = Number(validAfter)
322
+ if (Hex.validate(feeToken) && feeToken !== '0x')
323
+ transaction.feeToken = feeToken
324
+
325
+ // Parse calls array
326
+ if (calls && calls !== '0x') {
327
+ const callsArray = calls as unknown as readonly Hex.Hex[][]
328
+ transaction.calls = callsArray.map((callTuple) => {
329
+ const [to, value, data] = callTuple
330
+ const call: Call = {}
331
+ if (to && to !== '0x') call.to = to
332
+ if (value && value !== '0x') call.value = BigInt(value)
333
+ if (data && data !== '0x') call.data = data
334
+ return call
335
+ })
336
+ }
337
+
338
+ if (accessList?.length !== 0 && accessList !== '0x')
339
+ transaction.accessList = AccessList.fromTupleList(accessList as never)
340
+
341
+ if (authorizationList?.length !== 0 && authorizationList !== '0x')
342
+ transaction.authorizationList = AuthorizationTempo.fromTupleList(
343
+ authorizationList as never,
344
+ )
345
+
346
+ if (
347
+ feePayerSignatureOrSender !== '0x' &&
348
+ feePayerSignatureOrSender !== undefined
349
+ ) {
350
+ if (
351
+ feePayerSignatureOrSender === '0x00' ||
352
+ Address.validate(feePayerSignatureOrSender)
353
+ )
354
+ transaction.feePayerSignature = null
355
+ else
356
+ transaction.feePayerSignature = Signature.fromTuple(
357
+ feePayerSignatureOrSender as never,
358
+ )
359
+ }
360
+
361
+ if (keyAuthorization)
362
+ transaction.keyAuthorization = KeyAuthorization.fromTuple(
363
+ keyAuthorization as never,
364
+ )
365
+
366
+ const signatureEnvelope = signature
367
+ ? SignatureEnvelope.deserialize(signature)
368
+ : undefined
369
+ if (signatureEnvelope)
370
+ transaction = {
371
+ ...transaction,
372
+ signature: signatureEnvelope,
373
+ }
374
+
375
+ assert(transaction)
376
+
377
+ return transaction
378
+ }
379
+
380
+ export declare namespace deserialize {
381
+ type ErrorType = Errors.GlobalErrorType
382
+ }
383
+
384
+ /**
385
+ * Converts an arbitrary transaction object into a Tempo Transaction Envelope.
386
+ *
387
+ * Use this to create transaction envelopes with Tempo-specific features like batched calls,
388
+ * fee tokens, access keys, and scheduled execution. Attach a signature using the `signature`
389
+ * option after signing with {@link ox#TxEnvelopeTempo.(getSignPayload:function)}.
390
+ *
391
+ * [Tempo Transaction Specification](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction)
392
+ *
393
+ * @example
394
+ * ```ts twoslash
395
+ * import { Value } from 'ox'
396
+ * import { TxEnvelopeTempo } from 'ox/tempo'
397
+ *
398
+ * const envelope = TxEnvelopeTempo.from({ // [!code focus]
399
+ * chainId: 1, // [!code focus]
400
+ * calls: [{ // [!code focus]
401
+ * data: '0xdeadbeef', // [!code focus]
402
+ * to: '0x0000000000000000000000000000000000000000', // [!code focus]
403
+ * }], // [!code focus]
404
+ * maxFeePerGas: Value.fromGwei('10'), // [!code focus]
405
+ * maxPriorityFeePerGas: Value.fromGwei('1'), // [!code focus]
406
+ * }) // [!code focus]
407
+ * ```
408
+ *
409
+ * @example
410
+ * ### Attaching Signatures
411
+ *
412
+ * It is possible to attach a `signature` to the transaction envelope.
413
+ *
414
+ * ```ts twoslash
415
+ * // @noErrors
416
+ * import { Secp256k1, Value } from 'ox'
417
+ * import { TxEnvelopeTempo } from 'ox/tempo'
418
+ *
419
+ * const envelope = TxEnvelopeTempo.from({
420
+ * chainId: 1,
421
+ * calls: [{
422
+ * data: '0xdeadbeef',
423
+ * to: '0x0000000000000000000000000000000000000000',
424
+ * }],
425
+ * maxFeePerGas: Value.fromGwei('10'),
426
+ * maxPriorityFeePerGas: Value.fromGwei('1'),
427
+ * })
428
+ *
429
+ * const signature = Secp256k1.sign({
430
+ * payload: TxEnvelopeTempo.getSignPayload(envelope),
431
+ * privateKey: '0x...',
432
+ * })
433
+ *
434
+ * const envelope_signed = TxEnvelopeTempo.from(envelope, { // [!code focus]
435
+ * signature, // [!code focus]
436
+ * }) // [!code focus]
437
+ * // @log: {
438
+ * // @log: chainId: 1,
439
+ * // @log: calls: [{ to: '0x0000000000000000000000000000000000000000', value: 1000000000000000000n }],
440
+ * // @log: maxFeePerGas: 10000000000n,
441
+ * // @log: maxPriorityFeePerGas: 1000000000n,
442
+ * // @log: type: 'tempo',
443
+ * // @log: r: 125...n,
444
+ * // @log: s: 642...n,
445
+ * // @log: yParity: 0,
446
+ * // @log: }
447
+ * ```
448
+ *
449
+ * @example
450
+ * ### From Serialized
451
+ *
452
+ * It is possible to instantiate a Tempo Transaction Envelope from a {@link ox#TxEnvelopeTempo.Serialized} value.
453
+ *
454
+ * ```ts twoslash
455
+ * import { TxEnvelopeTempo } from 'ox/tempo'
456
+ *
457
+ * const envelope = TxEnvelopeTempo.from('0x76f84a0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0808080')
458
+ * // @log: {
459
+ * // @log: chainId: 1,
460
+ * // @log: calls: [{
461
+ * // @log: data: '0xdeadbeef',
462
+ * // @log: to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
463
+ * // @log: }],
464
+ * // @log: maxFeePerGas: 10000000000n,
465
+ * // @log: type: 'tempo',
466
+ * // @log: }
467
+ * ```
468
+ *
469
+ * @param envelope - The transaction object to convert.
470
+ * @param options - Options.
471
+ * @returns A Tempo Transaction Envelope.
472
+ */
473
+ export function from<
474
+ const envelope extends UnionPartialBy<TxEnvelopeTempo, 'type'> | Serialized,
475
+ const signature extends SignatureEnvelope.from.Value | undefined = undefined,
476
+ >(
477
+ envelope: envelope | UnionPartialBy<TxEnvelopeTempo, 'type'> | Serialized,
478
+ options: from.Options<signature> = {},
479
+ ): from.ReturnValue<envelope, signature> {
480
+ const { feePayerSignature, signature } = options
481
+
482
+ const envelope_ = (
483
+ typeof envelope === 'string' ? deserialize(envelope) : envelope
484
+ ) as TxEnvelopeTempo
485
+
486
+ assert(envelope_)
487
+
488
+ return {
489
+ ...envelope_,
490
+ ...(signature ? { signature: SignatureEnvelope.from(signature) } : {}),
491
+ ...(feePayerSignature
492
+ ? { feePayerSignature: Signature.from(feePayerSignature) }
493
+ : {}),
494
+ type: 'tempo',
495
+ } as never
496
+ }
497
+
498
+ export declare namespace from {
499
+ type Options<
500
+ signature extends SignatureEnvelope.from.Value | undefined = undefined,
501
+ > = {
502
+ feePayerSignature?: Signature.Signature | null | undefined
503
+ signature?: signature | SignatureEnvelope.from.Value | undefined
504
+ }
505
+
506
+ type ReturnValue<
507
+ envelope extends UnionPartialBy<TxEnvelopeTempo, 'type'> | Hex.Hex =
508
+ | TxEnvelopeTempo
509
+ | Hex.Hex,
510
+ signature extends SignatureEnvelope.from.Value | undefined = undefined,
511
+ > = Compute<
512
+ envelope extends Hex.Hex
513
+ ? TxEnvelopeTempo
514
+ : Assign<
515
+ envelope,
516
+ (signature extends SignatureEnvelope.from.Value
517
+ ? { signature: SignatureEnvelope.from.ReturnValue<signature> }
518
+ : {}) & {
519
+ readonly type: 'tempo'
520
+ }
521
+ >
522
+ >
523
+
524
+ type ErrorType =
525
+ | deserialize.ErrorType
526
+ | assert.ErrorType
527
+ | Errors.GlobalErrorType
528
+ }
529
+
530
+ /**
531
+ * Serializes a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo}.
532
+ *
533
+ * RLP-encodes the transaction with type prefix `0x76`. For fee sponsorship, use `format: 'feePayer'`
534
+ * to serialize with the fee payer magic `0x78` and the sender address.
535
+ *
536
+ * [RLP Encoding](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#rlp-encoding)
537
+ *
538
+ * @example
539
+ * ```ts twoslash
540
+ * // @noErrors
541
+ * import { Value } from 'ox'
542
+ * import { TxEnvelopeTempo } from 'ox/tempo'
543
+ *
544
+ * const envelope = TxEnvelopeTempo.from({
545
+ * chainId: 1,
546
+ * calls: [{
547
+ * data: '0xdeadbeef',
548
+ * to: '0x0000000000000000000000000000000000000000',
549
+ * }],
550
+ * maxFeePerGas: Value.fromGwei('10'),
551
+ * })
552
+ *
553
+ * const serialized = TxEnvelopeTempo.serialize(envelope) // [!code focus]
554
+ * ```
555
+ *
556
+ * @example
557
+ * ### Attaching Signatures
558
+ *
559
+ * It is possible to attach a `signature` to the serialized Transaction Envelope.
560
+ *
561
+ * ```ts twoslash
562
+ * // @noErrors
563
+ * import { Secp256k1, Value } from 'ox'
564
+ * import { TxEnvelopeTempo } from 'ox/tempo'
565
+ *
566
+ * const envelope = TxEnvelopeTempo.from({
567
+ * chainId: 1,
568
+ * calls: [{
569
+ * data: '0xdeadbeef',
570
+ * to: '0x0000000000000000000000000000000000000000',
571
+ * }],
572
+ * maxFeePerGas: Value.fromGwei('10'),
573
+ * })
574
+ *
575
+ * const signature = Secp256k1.sign({
576
+ * payload: TxEnvelopeTempo.getSignPayload(envelope),
577
+ * privateKey: '0x...',
578
+ * })
579
+ *
580
+ * const serialized = TxEnvelopeTempo.serialize(envelope, { // [!code focus]
581
+ * signature, // [!code focus]
582
+ * }) // [!code focus]
583
+ *
584
+ * // ... send `serialized` transaction to JSON-RPC `eth_sendRawTransaction`
585
+ * ```
586
+ *
587
+ * @param envelope - The Transaction Envelope to serialize.
588
+ * @param options - Options.
589
+ * @returns The serialized Transaction Envelope.
590
+ */
591
+ export function serialize(
592
+ envelope: PartialBy<TxEnvelopeTempo, 'type'>,
593
+ options: serialize.Options = {},
594
+ ): Serialized {
595
+ const {
596
+ accessList,
597
+ authorizationList,
598
+ calls,
599
+ chainId,
600
+ feeToken,
601
+ gas,
602
+ keyAuthorization,
603
+ nonce,
604
+ nonceKey,
605
+ maxFeePerGas,
606
+ maxPriorityFeePerGas,
607
+ validBefore,
608
+ validAfter,
609
+ } = envelope
610
+
611
+ assert(envelope)
612
+
613
+ const accessTupleList = AccessList.toTupleList(accessList)
614
+ const signature = options.signature || envelope.signature
615
+
616
+ const authorizationTupleList =
617
+ AuthorizationTempo.toTupleList(authorizationList)
618
+
619
+ // Encode calls as RLP list of [to, value, data] tuples
620
+ const callsTupleList = calls.map((call) => [
621
+ call.to ?? '0x',
622
+ call.value ? Hex.fromNumber(call.value) : '0x',
623
+ call.data ?? '0x',
624
+ ])
625
+
626
+ const feePayerSignatureOrSender = (() => {
627
+ if (options.sender) return options.sender
628
+ const feePayerSignature =
629
+ typeof options.feePayerSignature !== 'undefined'
630
+ ? options.feePayerSignature
631
+ : envelope.feePayerSignature
632
+ if (feePayerSignature === null) return '0x00'
633
+ if (!feePayerSignature) return '0x'
634
+ return Signature.toTuple(feePayerSignature)
635
+ })()
636
+
637
+ const serialized = [
638
+ Hex.fromNumber(chainId),
639
+ maxPriorityFeePerGas ? Hex.fromNumber(maxPriorityFeePerGas) : '0x',
640
+ maxFeePerGas ? Hex.fromNumber(maxFeePerGas) : '0x',
641
+ gas ? Hex.fromNumber(gas) : '0x',
642
+ callsTupleList,
643
+ accessTupleList,
644
+ nonceKey ? Hex.fromNumber(nonceKey) : '0x',
645
+ nonce ? Hex.fromNumber(nonce) : '0x',
646
+ typeof validBefore === 'number' ? Hex.fromNumber(validBefore) : '0x',
647
+ typeof validAfter === 'number' ? Hex.fromNumber(validAfter) : '0x',
648
+ typeof feeToken === 'bigint' || typeof feeToken === 'string'
649
+ ? TokenId.toAddress(feeToken)
650
+ : '0x',
651
+ feePayerSignatureOrSender,
652
+ authorizationTupleList,
653
+ ...(keyAuthorization ? [KeyAuthorization.toTuple(keyAuthorization)] : []),
654
+ ...(signature
655
+ ? [SignatureEnvelope.serialize(SignatureEnvelope.from(signature))]
656
+ : []),
657
+ ] as const
658
+
659
+ return Hex.concat(
660
+ options.format === 'feePayer' ? feePayerMagic : serializedType,
661
+ Rlp.fromHex(serialized),
662
+ ) as Serialized
663
+ }
664
+
665
+ export declare namespace serialize {
666
+ type Options = {
667
+ /**
668
+ * Sender signature to append to the serialized envelope.
669
+ */
670
+ signature?: SignatureEnvelope.from.Value | undefined
671
+ } & OneOf<
672
+ | {
673
+ /**
674
+ * Sender address to cover the fee of.
675
+ */
676
+ sender: Address.Address
677
+ /**
678
+ * Whether to serialize the transaction in the fee payer format.
679
+ *
680
+ * - If `'feePayer'`, then the transaction will be serialized in the fee payer format.
681
+ * - If `undefined` (default), then the transaction will be serialized in the normal format.
682
+ */
683
+ format: 'feePayer'
684
+ }
685
+ | {
686
+ /**
687
+ * Fee payer signature or the sender to cover the fee of.
688
+ *
689
+ * - If `Signature.Signature`, then this is the fee payer signature.
690
+ * - If `null`, then this indicates the envelope is intended to be signed by a fee payer.
691
+ */
692
+ feePayerSignature?: Signature.Signature | null | undefined
693
+ format?: undefined
694
+ }
695
+ >
696
+
697
+ type ErrorType =
698
+ | assert.ErrorType
699
+ | Hex.fromNumber.ErrorType
700
+ | Signature.toTuple.ErrorType
701
+ | Hex.concat.ErrorType
702
+ | Rlp.fromHex.ErrorType
703
+ | Errors.GlobalErrorType
704
+ }
705
+
706
+ /**
707
+ * Returns the payload to sign for a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo}.
708
+ *
709
+ * Computes the keccak256 hash of the unsigned serialized transaction. Sign this payload
710
+ * with secp256k1, P256, or WebAuthn, then attach the signature via {@link ox#TxEnvelopeTempo.(from:function)}.
711
+ *
712
+ * [Tempo Transaction Specification](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction)
713
+ *
714
+ * @example
715
+ * The example below demonstrates how to compute the sign payload which can be used
716
+ * with ECDSA signing utilities like {@link ox#Secp256k1.(sign:function)}.
717
+ *
718
+ * ```ts twoslash
719
+ * // @noErrors
720
+ * import { Secp256k1 } from 'ox'
721
+ * import { TxEnvelopeTempo } from 'ox/tempo'
722
+ *
723
+ * const envelope = TxEnvelopeTempo.from({
724
+ * chainId: 1,
725
+ * calls: [{
726
+ * data: '0xdeadbeef',
727
+ * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
728
+ * }],
729
+ * nonce: 0n,
730
+ * maxFeePerGas: 1000000000n,
731
+ * gas: 21000n,
732
+ * })
733
+ *
734
+ * const payload = TxEnvelopeTempo.getSignPayload(envelope) // [!code focus]
735
+ * // @log: '0x...'
736
+ *
737
+ * const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
738
+ * ```
739
+ *
740
+ * @param envelope - The transaction envelope to get the sign payload for.
741
+ * @returns The sign payload.
742
+ */
743
+ export function getSignPayload(
744
+ envelope: TxEnvelopeTempo,
745
+ ): getSignPayload.ReturnValue {
746
+ return hash(envelope, { presign: true })
747
+ }
748
+
749
+ export declare namespace getSignPayload {
750
+ type ReturnValue = Hex.Hex
751
+
752
+ type ErrorType = hash.ErrorType | Errors.GlobalErrorType
753
+ }
754
+
755
+ /**
756
+ * Hashes a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo}. This is the "transaction hash".
757
+ *
758
+ * @example
759
+ * ```ts twoslash
760
+ * // @noErrors
761
+ * import { Secp256k1 } from 'ox'
762
+ * import { TxEnvelopeTempo } from 'ox/tempo'
763
+ *
764
+ * const envelope = TxEnvelopeTempo.from({
765
+ * chainId: 1,
766
+ * calls: [{
767
+ * data: '0xdeadbeef',
768
+ * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
769
+ * }],
770
+ * nonce: 0n,
771
+ * maxFeePerGas: 1000000000n,
772
+ * gas: 21000n,
773
+ * })
774
+ *
775
+ * const signature = Secp256k1.sign({
776
+ * payload: TxEnvelopeTempo.getSignPayload(envelope),
777
+ * privateKey: '0x...'
778
+ * })
779
+ *
780
+ * const envelope_signed = TxEnvelopeTempo.from(envelope, { signature })
781
+ *
782
+ * const hash = TxEnvelopeTempo.hash(envelope_signed) // [!code focus]
783
+ * ```
784
+ *
785
+ * @param envelope - The Tempo Transaction Envelope to hash.
786
+ * @param options - Options.
787
+ * @returns The hash of the transaction envelope.
788
+ */
789
+ export function hash<presign extends boolean = false>(
790
+ envelope: TxEnvelopeTempo<presign extends true ? false : true>,
791
+ options: hash.Options<presign> = {},
792
+ ): hash.ReturnValue {
793
+ const serialized = serialize({
794
+ ...envelope,
795
+ ...(options.presign
796
+ ? {
797
+ signature: undefined,
798
+ }
799
+ : {}),
800
+ })
801
+ return Hash.keccak256(serialized)
802
+ }
803
+
804
+ export declare namespace hash {
805
+ type Options<presign extends boolean = false> = {
806
+ /**
807
+ * Whether to hash this transaction for signing.
808
+ *
809
+ * @default false
810
+ */
811
+ presign?: presign | boolean | undefined
812
+ }
813
+
814
+ type ReturnValue = Hex.Hex
815
+
816
+ type ErrorType =
817
+ | Hash.keccak256.ErrorType
818
+ | serialize.ErrorType
819
+ | Errors.GlobalErrorType
820
+ }
821
+
822
+ /**
823
+ * Returns the fee payer payload to sign for a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo}.
824
+ *
825
+ * Fee sponsorship uses a dual-signature scheme: the sender signs the transaction, then a fee payer
826
+ * signs over the transaction with the sender's address to commit to paying fees. The fee payer's
827
+ * signature includes the `feeToken` and `sender_address`, using magic byte `0x78` for domain separation.
828
+ *
829
+ * [Fee Payer Signature](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#fee-payer-signature)
830
+ * [Fee Sponsorship Guide](https://docs.tempo.xyz/protocol/transactions#fee-sponsorship)
831
+ *
832
+ * @example
833
+ * ```ts twoslash
834
+ * // @noErrors
835
+ * import { Secp256k1 } from 'ox'
836
+ * import { TxEnvelopeTempo } from 'ox/tempo'
837
+ *
838
+ * const envelope = TxEnvelopeTempo.from({
839
+ * chainId: 1,
840
+ * calls: [{
841
+ * data: '0xdeadbeef',
842
+ * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
843
+ * }],
844
+ * nonce: 0n,
845
+ * maxFeePerGas: 1000000000n,
846
+ * gas: 21000n,
847
+ * })
848
+ *
849
+ * const payload = TxEnvelopeTempo.getFeePayerSignPayload(envelope, {
850
+ * sender: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045'
851
+ * }) // [!code focus]
852
+ * // @log: '0x...'
853
+ *
854
+ * const signature = Secp256k1.sign({ payload, privateKey: '0x...' })
855
+ * ```
856
+ *
857
+ * @param envelope - The transaction envelope to get the fee payer sign payload for.
858
+ * @param options - Options.
859
+ * @returns The fee payer sign payload.
860
+ */
861
+ export function getFeePayerSignPayload(
862
+ envelope: TxEnvelopeTempo,
863
+ options: getFeePayerSignPayload.Options,
864
+ ): getFeePayerSignPayload.ReturnValue {
865
+ const { sender } = options
866
+ const serialized = serialize(
867
+ { ...envelope, signature: undefined },
868
+ {
869
+ sender,
870
+ format: 'feePayer',
871
+ },
872
+ )
873
+ return Hash.keccak256(serialized)
874
+ }
875
+
876
+ export declare namespace getFeePayerSignPayload {
877
+ type Options = {
878
+ /**
879
+ * Sender address to cover the fee of.
880
+ */
881
+ sender: Address.Address
882
+ }
883
+
884
+ type ReturnValue = Hex.Hex
885
+
886
+ type ErrorType = hash.ErrorType | Errors.GlobalErrorType
887
+ }
888
+
889
+ /**
890
+ * Validates a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo}. Returns `true` if the envelope is valid, `false` otherwise.
891
+ *
892
+ * @example
893
+ * ```ts twoslash
894
+ * import { TxEnvelopeTempo } from 'ox/tempo'
895
+ *
896
+ * const valid = TxEnvelopeTempo.validate({
897
+ * calls: [{
898
+ * data: '0xdeadbeef',
899
+ * to: '0x0000000000000000000000000000000000000000',
900
+ * }],
901
+ * chainId: 1,
902
+ * maxFeePerGas: 1000000000n,
903
+ * })
904
+ * // @log: true
905
+ * ```
906
+ *
907
+ * @param envelope - The transaction envelope to validate.
908
+ */
909
+ export function validate(envelope: PartialBy<TxEnvelopeTempo, 'type'>) {
910
+ try {
911
+ assert(envelope)
912
+ return true
913
+ } catch {
914
+ return false
915
+ }
916
+ }
917
+
918
+ export declare namespace validate {
919
+ type ErrorType = Errors.GlobalErrorType
920
+ }
921
+
922
+ /**
923
+ * Thrown when a transaction's calls list is empty.
924
+ *
925
+ * @example
926
+ * ```ts twoslash
927
+ * import { TxEnvelopeTempo } from 'ox/tempo'
928
+ *
929
+ * TxEnvelopeTempo.assert({
930
+ * calls: [],
931
+ * chainId: 1,
932
+ * })
933
+ * // @error: TxEnvelopeTempo.CallsEmptyError: Calls list cannot be empty.
934
+ * ```
935
+ */
936
+ export class CallsEmptyError extends Errors.BaseError {
937
+ override readonly name = 'TxEnvelopeTempo.CallsEmptyError'
938
+ constructor() {
939
+ super('Calls list cannot be empty.')
940
+ }
941
+ }
942
+
943
+ /**
944
+ * Thrown when validBefore is not greater than validAfter.
945
+ *
946
+ * @example
947
+ * ```ts twoslash
948
+ * import { TxEnvelopeTempo } from 'ox/tempo'
949
+ *
950
+ * TxEnvelopeTempo.assert({
951
+ * calls: [{ to: '0x0000000000000000000000000000000000000000' }],
952
+ * chainId: 1,
953
+ * validBefore: 100,
954
+ * validAfter: 200,
955
+ * })
956
+ * // @error: TxEnvelopeTempo.InvalidValidityWindowError: validBefore (100) must be greater than validAfter (200).
957
+ * ```
958
+ */
959
+ export class InvalidValidityWindowError extends Errors.BaseError {
960
+ override readonly name = 'TxEnvelopeTempo.InvalidValidityWindowError'
961
+ constructor({
962
+ validBefore,
963
+ validAfter,
964
+ }: {
965
+ validBefore: number
966
+ validAfter: number
967
+ }) {
968
+ super(
969
+ `validBefore (${validBefore}) must be greater than validAfter (${validAfter}).`,
970
+ )
971
+ }
972
+ }