tempo.ts 0.0.5 → 0.1.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 (195) hide show
  1. package/dist/chains.d.ts +244 -541
  2. package/dist/chains.d.ts.map +1 -1
  3. package/dist/chains.js +10 -23
  4. package/dist/chains.js.map +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/ox/SignatureEnvelope.d.ts +245 -0
  7. package/dist/ox/SignatureEnvelope.d.ts.map +1 -0
  8. package/dist/ox/SignatureEnvelope.js +437 -0
  9. package/dist/ox/SignatureEnvelope.js.map +1 -0
  10. package/dist/ox/Transaction.d.ts +61 -24
  11. package/dist/ox/Transaction.d.ts.map +1 -1
  12. package/dist/ox/Transaction.js +63 -18
  13. package/dist/ox/Transaction.js.map +1 -1
  14. package/dist/ox/TransactionEnvelopeAA.d.ts +461 -0
  15. package/dist/ox/TransactionEnvelopeAA.d.ts.map +1 -0
  16. package/dist/ox/TransactionEnvelopeAA.js +528 -0
  17. package/dist/ox/TransactionEnvelopeAA.js.map +1 -0
  18. package/dist/ox/TransactionRequest.d.ts +7 -5
  19. package/dist/ox/TransactionRequest.d.ts.map +1 -1
  20. package/dist/ox/TransactionRequest.js +21 -12
  21. package/dist/ox/TransactionRequest.js.map +1 -1
  22. package/dist/ox/index.d.ts +5 -4
  23. package/dist/ox/index.d.ts.map +1 -1
  24. package/dist/ox/index.js +5 -4
  25. package/dist/ox/index.js.map +1 -1
  26. package/dist/prool/Instance.d.ts +0 -4
  27. package/dist/prool/Instance.d.ts.map +1 -1
  28. package/dist/prool/Instance.js +7 -7
  29. package/dist/prool/Instance.js.map +1 -1
  30. package/dist/prool/index.d.ts +1 -1
  31. package/dist/prool/index.d.ts.map +1 -1
  32. package/dist/prool/index.js +1 -1
  33. package/dist/prool/index.js.map +1 -1
  34. package/dist/viem/{abis.d.ts → Abis.d.ts} +523 -9
  35. package/dist/viem/Abis.d.ts.map +1 -0
  36. package/dist/viem/{abis.js → Abis.js} +321 -9
  37. package/dist/viem/Abis.js.map +1 -0
  38. package/dist/viem/{actions → Actions}/amm.d.ts +21 -21
  39. package/dist/viem/Actions/amm.d.ts.map +1 -0
  40. package/dist/viem/{actions → Actions}/amm.js +55 -43
  41. package/dist/viem/Actions/amm.js.map +1 -0
  42. package/dist/viem/Actions/dex.d.ts +3263 -0
  43. package/dist/viem/Actions/dex.d.ts.map +1 -0
  44. package/dist/viem/Actions/dex.js +1357 -0
  45. package/dist/viem/Actions/dex.js.map +1 -0
  46. package/dist/viem/{actions → Actions}/fee.d.ts +8 -8
  47. package/dist/viem/Actions/fee.d.ts.map +1 -0
  48. package/dist/viem/{actions → Actions}/fee.js +14 -13
  49. package/dist/viem/Actions/fee.js.map +1 -0
  50. package/dist/viem/Actions/index.d.ts +6 -0
  51. package/dist/viem/Actions/index.d.ts.map +1 -0
  52. package/dist/viem/Actions/index.js +6 -0
  53. package/dist/viem/Actions/index.js.map +1 -0
  54. package/dist/viem/{actions → Actions}/policy.d.ts +19 -19
  55. package/dist/viem/Actions/policy.d.ts.map +1 -0
  56. package/dist/viem/{actions → Actions}/policy.js +59 -46
  57. package/dist/viem/Actions/policy.js.map +1 -0
  58. package/dist/viem/{actions → Actions}/token.d.ts +3251 -707
  59. package/dist/viem/Actions/token.d.ts.map +1 -0
  60. package/dist/viem/{actions → Actions}/token.js +420 -88
  61. package/dist/viem/Actions/token.js.map +1 -0
  62. package/dist/viem/Addresses.d.ts +9 -0
  63. package/dist/viem/Addresses.d.ts.map +1 -0
  64. package/dist/viem/Addresses.js +9 -0
  65. package/dist/viem/Addresses.js.map +1 -0
  66. package/dist/viem/{chain.d.ts → Chain.d.ts} +81 -57
  67. package/dist/viem/Chain.d.ts.map +1 -0
  68. package/dist/viem/{chain.js → Chain.js} +7 -7
  69. package/dist/viem/Chain.js.map +1 -0
  70. package/dist/viem/{client.d.ts → Client.d.ts} +4 -4
  71. package/dist/viem/Client.d.ts.map +1 -0
  72. package/dist/viem/{client.js → Client.js} +3 -3
  73. package/dist/viem/Client.js.map +1 -0
  74. package/dist/viem/{decorator.d.ts → Decorator.d.ts} +507 -5
  75. package/dist/viem/Decorator.d.ts.map +1 -0
  76. package/dist/viem/{decorator.js → Decorator.js} +31 -5
  77. package/dist/viem/Decorator.js.map +1 -0
  78. package/dist/viem/{formatters.d.ts → Formatters.d.ts} +2 -2
  79. package/dist/viem/Formatters.d.ts.map +1 -0
  80. package/dist/viem/{formatters.js → Formatters.js} +24 -17
  81. package/dist/viem/Formatters.js.map +1 -0
  82. package/dist/viem/Tick.d.ts +111 -0
  83. package/dist/viem/Tick.d.ts.map +1 -0
  84. package/dist/viem/Tick.js +127 -0
  85. package/dist/viem/Tick.js.map +1 -0
  86. package/dist/viem/TokenIds.d.ts +3 -0
  87. package/dist/viem/TokenIds.d.ts.map +1 -0
  88. package/dist/viem/TokenIds.js +3 -0
  89. package/dist/viem/TokenIds.js.map +1 -0
  90. package/dist/viem/Transaction.d.ts +57 -0
  91. package/dist/viem/Transaction.d.ts.map +1 -0
  92. package/dist/viem/Transaction.js +137 -0
  93. package/dist/viem/Transaction.js.map +1 -0
  94. package/dist/viem/{transport.d.ts → Transport.d.ts} +3 -3
  95. package/dist/viem/Transport.d.ts.map +1 -0
  96. package/dist/viem/{transport.js → Transport.js} +3 -3
  97. package/dist/viem/Transport.js.map +1 -0
  98. package/dist/viem/index.d.ts +13 -9
  99. package/dist/viem/index.d.ts.map +1 -1
  100. package/dist/viem/index.js +13 -9
  101. package/dist/viem/index.js.map +1 -1
  102. package/dist/viem/{types.d.ts → internal/types.d.ts} +3 -3
  103. package/dist/viem/internal/types.d.ts.map +1 -0
  104. package/dist/viem/{types.js.map → internal/types.js.map} +1 -1
  105. package/dist/viem/internal/utils.d.ts.map +1 -0
  106. package/dist/viem/internal/utils.js.map +1 -0
  107. package/package.json +87 -101
  108. package/src/chains.ts +10 -24
  109. package/src/ox/SignatureEnvelope.test.ts +1252 -0
  110. package/src/ox/SignatureEnvelope.ts +709 -0
  111. package/src/ox/Transaction.test.ts +144 -89
  112. package/src/ox/Transaction.ts +104 -29
  113. package/src/ox/TransactionEnvelopeAA.test.ts +1533 -0
  114. package/src/ox/TransactionEnvelopeAA.ts +858 -0
  115. package/src/ox/TransactionRequest.ts +25 -17
  116. package/src/ox/index.ts +2 -1
  117. package/src/prool/Instance.ts +6 -14
  118. package/src/prool/internal/chain.json +101 -27
  119. package/src/viem/{abis.ts → Abis.ts} +322 -8
  120. package/src/viem/{actions → Actions}/amm.test.ts +65 -68
  121. package/src/viem/{actions → Actions}/amm.ts +72 -60
  122. package/src/viem/Actions/dex.test.ts +1608 -0
  123. package/src/viem/Actions/dex.ts +2026 -0
  124. package/src/viem/{actions → Actions}/fee.test.ts +34 -36
  125. package/src/viem/{actions → Actions}/fee.ts +18 -17
  126. package/src/viem/{actions → Actions}/index.ts +1 -0
  127. package/src/viem/{actions → Actions}/policy.test.ts +2 -2
  128. package/src/viem/{actions → Actions}/policy.ts +77 -64
  129. package/src/viem/{actions → Actions}/token.test.ts +406 -67
  130. package/src/viem/{actions → Actions}/token.ts +675 -144
  131. package/src/viem/Addresses.ts +9 -0
  132. package/src/viem/{chain.ts → Chain.ts} +6 -6
  133. package/src/viem/{client.bench-d.ts → Client.bench-d.ts} +2 -2
  134. package/src/viem/{client.test.ts → Client.test.ts} +31 -6
  135. package/src/viem/{client.ts → Client.ts} +1 -1
  136. package/src/viem/{decorator.bench-d.ts → Decorator.bench-d.ts} +2 -2
  137. package/src/viem/{decorator.test.ts → Decorator.test.ts} +1 -0
  138. package/src/viem/{decorator.ts → Decorator.ts} +586 -4
  139. package/src/viem/{formatters.ts → Formatters.ts} +31 -20
  140. package/src/viem/Tick.test.ts +281 -0
  141. package/src/viem/Tick.ts +176 -0
  142. package/src/viem/TokenIds.ts +2 -0
  143. package/src/viem/Transaction.ts +303 -0
  144. package/src/viem/{transport.ts → Transport.ts} +5 -5
  145. package/src/viem/e2e.test.ts +153 -78
  146. package/src/viem/index.ts +13 -9
  147. package/src/viem/{types.ts → internal/types.ts} +3 -3
  148. package/dist/ox/TransactionEnvelopeFeeToken.d.ts +0 -393
  149. package/dist/ox/TransactionEnvelopeFeeToken.d.ts.map +0 -1
  150. package/dist/ox/TransactionEnvelopeFeeToken.js +0 -452
  151. package/dist/ox/TransactionEnvelopeFeeToken.js.map +0 -1
  152. package/dist/viem/abis.d.ts.map +0 -1
  153. package/dist/viem/abis.js.map +0 -1
  154. package/dist/viem/actions/amm.d.ts.map +0 -1
  155. package/dist/viem/actions/amm.js.map +0 -1
  156. package/dist/viem/actions/fee.d.ts.map +0 -1
  157. package/dist/viem/actions/fee.js.map +0 -1
  158. package/dist/viem/actions/index.d.ts +0 -5
  159. package/dist/viem/actions/index.d.ts.map +0 -1
  160. package/dist/viem/actions/index.js +0 -5
  161. package/dist/viem/actions/index.js.map +0 -1
  162. package/dist/viem/actions/policy.d.ts.map +0 -1
  163. package/dist/viem/actions/policy.js.map +0 -1
  164. package/dist/viem/actions/token.d.ts.map +0 -1
  165. package/dist/viem/actions/token.js.map +0 -1
  166. package/dist/viem/addresses.d.ts +0 -8
  167. package/dist/viem/addresses.d.ts.map +0 -1
  168. package/dist/viem/addresses.js +0 -8
  169. package/dist/viem/addresses.js.map +0 -1
  170. package/dist/viem/chain.d.ts.map +0 -1
  171. package/dist/viem/chain.js.map +0 -1
  172. package/dist/viem/client.d.ts.map +0 -1
  173. package/dist/viem/client.js.map +0 -1
  174. package/dist/viem/decorator.d.ts.map +0 -1
  175. package/dist/viem/decorator.js.map +0 -1
  176. package/dist/viem/formatters.d.ts.map +0 -1
  177. package/dist/viem/formatters.js.map +0 -1
  178. package/dist/viem/transaction.d.ts +0 -54
  179. package/dist/viem/transaction.d.ts.map +0 -1
  180. package/dist/viem/transaction.js +0 -108
  181. package/dist/viem/transaction.js.map +0 -1
  182. package/dist/viem/transport.d.ts.map +0 -1
  183. package/dist/viem/transport.js.map +0 -1
  184. package/dist/viem/types.d.ts.map +0 -1
  185. package/dist/viem/utils.d.ts.map +0 -1
  186. package/dist/viem/utils.js.map +0 -1
  187. package/src/ox/TransactionEnvelopeFeeToken.test.ts +0 -1119
  188. package/src/ox/TransactionEnvelopeFeeToken.ts +0 -717
  189. package/src/prool/internal/consensus.toml +0 -32
  190. package/src/viem/addresses.ts +0 -10
  191. package/src/viem/transaction.ts +0 -253
  192. /package/dist/viem/{types.js → internal/types.js} +0 -0
  193. /package/dist/viem/{utils.d.ts → internal/utils.d.ts} +0 -0
  194. /package/dist/viem/{utils.js → internal/utils.js} +0 -0
  195. /package/src/viem/{utils.ts → internal/utils.ts} +0 -0
@@ -0,0 +1,1533 @@
1
+ import {
2
+ Address,
3
+ Hex,
4
+ P256,
5
+ Rlp,
6
+ RpcTransport,
7
+ Secp256k1,
8
+ Value,
9
+ WebAuthnP256,
10
+ } from 'ox'
11
+ import { createClient, http, parseEther } from 'viem'
12
+ import { privateKeyToAccount } from 'viem/accounts'
13
+ import { afterEach, beforeEach, describe, expect, test } from 'vitest'
14
+ import { tempoLocal } from '../chains.js'
15
+ import { Instance } from '../prool/index.js'
16
+ import { Actions } from '../viem/index.js'
17
+ import { SignatureEnvelope } from './index.js'
18
+ import * as Transaction from './Transaction.js'
19
+ import * as TransactionEnvelopeAA from './TransactionEnvelopeAA.js'
20
+
21
+ const privateKey =
22
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
23
+
24
+ describe('assert', () => {
25
+ test('empty calls list', () => {
26
+ expect(() =>
27
+ TransactionEnvelopeAA.assert({
28
+ calls: [],
29
+ chainId: 1,
30
+ }),
31
+ ).toThrowErrorMatchingInlineSnapshot(
32
+ `[TransactionEnvelopeAA.CallsEmptyError: Calls list cannot be empty.]`,
33
+ )
34
+ })
35
+
36
+ test('missing calls', () => {
37
+ expect(() =>
38
+ TransactionEnvelopeAA.assert({
39
+ chainId: 1,
40
+ } as any),
41
+ ).toThrowErrorMatchingInlineSnapshot(
42
+ `[TransactionEnvelopeAA.CallsEmptyError: Calls list cannot be empty.]`,
43
+ )
44
+ })
45
+
46
+ test('invalid validity window', () => {
47
+ expect(() =>
48
+ TransactionEnvelopeAA.assert({
49
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
50
+ chainId: 1,
51
+ validBefore: 100,
52
+ validAfter: 200,
53
+ }),
54
+ ).toThrowErrorMatchingInlineSnapshot(
55
+ `[TransactionEnvelopeAA.InvalidValidityWindowError: validBefore (100) must be greater than validAfter (200).]`,
56
+ )
57
+ })
58
+
59
+ test('invalid validity window (equal)', () => {
60
+ expect(() =>
61
+ TransactionEnvelopeAA.assert({
62
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
63
+ chainId: 1,
64
+ validBefore: 100,
65
+ validAfter: 100,
66
+ }),
67
+ ).toThrowErrorMatchingInlineSnapshot(
68
+ `[TransactionEnvelopeAA.InvalidValidityWindowError: validBefore (100) must be greater than validAfter (100).]`,
69
+ )
70
+ })
71
+
72
+ test('invalid call address', () => {
73
+ expect(() =>
74
+ TransactionEnvelopeAA.assert({
75
+ calls: [{ to: '0x000000000000000000000000000000000000000z' }],
76
+ chainId: 1,
77
+ }),
78
+ ).toThrowErrorMatchingInlineSnapshot(
79
+ `
80
+ [Address.InvalidAddressError: Address "0x000000000000000000000000000000000000000z" is invalid.
81
+
82
+ Details: Address is not a 20 byte (40 hexadecimal character) value.]
83
+ `,
84
+ )
85
+ })
86
+
87
+ test('fee cap too high', () => {
88
+ expect(() =>
89
+ TransactionEnvelopeAA.assert({
90
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
91
+ maxFeePerGas: 2n ** 256n - 1n + 1n,
92
+ chainId: 1,
93
+ }),
94
+ ).toThrowErrorMatchingInlineSnapshot(
95
+ `[TransactionEnvelope.FeeCapTooHighError: The fee cap (\`maxFeePerGas\`/\`maxPriorityFeePerGas\` = 115792089237316195423570985008687907853269984665640564039457584007913.129639936 gwei) cannot be higher than the maximum allowed value (2^256-1).]`,
96
+ )
97
+ })
98
+
99
+ test('tip above fee cap', () => {
100
+ expect(() =>
101
+ TransactionEnvelopeAA.assert({
102
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
103
+ chainId: 1,
104
+ maxFeePerGas: 10n,
105
+ maxPriorityFeePerGas: 20n,
106
+ }),
107
+ ).toThrowErrorMatchingInlineSnapshot(
108
+ `[TransactionEnvelope.TipAboveFeeCapError: The provided tip (\`maxPriorityFeePerGas\` = 0.00000002 gwei) cannot be higher than the fee cap (\`maxFeePerGas\` = 0.00000001 gwei).]`,
109
+ )
110
+ })
111
+
112
+ test('invalid chain id', () => {
113
+ expect(() =>
114
+ TransactionEnvelopeAA.assert({
115
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
116
+ chainId: 0,
117
+ }),
118
+ ).toThrowErrorMatchingInlineSnapshot(
119
+ `[TransactionEnvelope.InvalidChainIdError: Chain ID "0" is invalid.]`,
120
+ )
121
+ })
122
+ })
123
+
124
+ describe('deserialize', () => {
125
+ const transaction = TransactionEnvelopeAA.from({
126
+ chainId: 1,
127
+ calls: [
128
+ {
129
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
130
+ value: Value.fromEther('1'),
131
+ },
132
+ ],
133
+ nonce: 785n,
134
+ nonceKey: 0n,
135
+ maxFeePerGas: Value.fromGwei('2'),
136
+ maxPriorityFeePerGas: Value.fromGwei('2'),
137
+ })
138
+
139
+ test('default', () => {
140
+ const serialized = TransactionEnvelopeAA.serialize(transaction)
141
+ const deserialized = TransactionEnvelopeAA.deserialize(serialized)
142
+ expect(deserialized).toEqual(transaction)
143
+ })
144
+
145
+ test('minimal', () => {
146
+ const transaction = TransactionEnvelopeAA.from({
147
+ chainId: 1,
148
+ calls: [{}],
149
+ nonce: 0n,
150
+ nonceKey: 0n,
151
+ })
152
+ const serialized = TransactionEnvelopeAA.serialize(transaction)
153
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(transaction)
154
+ })
155
+
156
+ test('multiple calls', () => {
157
+ const transaction_multiCall = TransactionEnvelopeAA.from({
158
+ ...transaction,
159
+ calls: [
160
+ {
161
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
162
+ value: Value.fromEther('1'),
163
+ },
164
+ {
165
+ to: '0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc',
166
+ value: Value.fromEther('2'),
167
+ data: '0x1234',
168
+ },
169
+ ],
170
+ })
171
+ const serialized = TransactionEnvelopeAA.serialize(transaction_multiCall)
172
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
173
+ transaction_multiCall,
174
+ )
175
+ })
176
+
177
+ test('gas', () => {
178
+ const transaction_gas = TransactionEnvelopeAA.from({
179
+ ...transaction,
180
+ gas: 21001n,
181
+ })
182
+ const serialized = TransactionEnvelopeAA.serialize(transaction_gas)
183
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
184
+ transaction_gas,
185
+ )
186
+ })
187
+
188
+ test('accessList', () => {
189
+ const transaction_accessList = TransactionEnvelopeAA.from({
190
+ ...transaction,
191
+ accessList: [
192
+ {
193
+ address: '0x0000000000000000000000000000000000000000',
194
+ storageKeys: [
195
+ '0x0000000000000000000000000000000000000000000000000000000000000001',
196
+ '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe',
197
+ ],
198
+ },
199
+ ],
200
+ })
201
+ const serialized = TransactionEnvelopeAA.serialize(transaction_accessList)
202
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
203
+ transaction_accessList,
204
+ )
205
+ })
206
+
207
+ test('nonce', () => {
208
+ const transaction_nonce = TransactionEnvelopeAA.from({
209
+ ...transaction,
210
+ nonce: 0n,
211
+ })
212
+ const serialized = TransactionEnvelopeAA.serialize(transaction_nonce)
213
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
214
+ transaction_nonce,
215
+ )
216
+ })
217
+
218
+ test('nonceKey', () => {
219
+ const transaction_nonceKey = TransactionEnvelopeAA.from({
220
+ ...transaction,
221
+ nonceKey: 0n,
222
+ })
223
+ const serialized = TransactionEnvelopeAA.serialize(transaction_nonceKey)
224
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
225
+ transaction_nonceKey,
226
+ )
227
+ })
228
+
229
+ test('validBefore', () => {
230
+ const transaction_validBefore = TransactionEnvelopeAA.from({
231
+ ...transaction,
232
+ validBefore: 1000000,
233
+ })
234
+ const serialized = TransactionEnvelopeAA.serialize(transaction_validBefore)
235
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
236
+ transaction_validBefore,
237
+ )
238
+ })
239
+
240
+ test('validAfter', () => {
241
+ const transaction_validAfter = TransactionEnvelopeAA.from({
242
+ ...transaction,
243
+ validAfter: 500000,
244
+ })
245
+ const serialized = TransactionEnvelopeAA.serialize(transaction_validAfter)
246
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
247
+ transaction_validAfter,
248
+ )
249
+ })
250
+
251
+ test('validBefore and validAfter', () => {
252
+ const transaction_validity = TransactionEnvelopeAA.from({
253
+ ...transaction,
254
+ validBefore: 1000000,
255
+ validAfter: 500000,
256
+ })
257
+ const serialized = TransactionEnvelopeAA.serialize(transaction_validity)
258
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
259
+ transaction_validity,
260
+ )
261
+ })
262
+
263
+ test('feeToken', () => {
264
+ const transaction_feeToken = TransactionEnvelopeAA.from({
265
+ ...transaction,
266
+ feeToken: '0x20c0000000000000000000000000000000000000',
267
+ })
268
+ const serialized = TransactionEnvelopeAA.serialize(transaction_feeToken)
269
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
270
+ transaction_feeToken,
271
+ )
272
+ })
273
+
274
+ describe('signature', () => {
275
+ test('secp256k1', () => {
276
+ const signature = Secp256k1.sign({
277
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
278
+ privateKey,
279
+ })
280
+ const serialized = TransactionEnvelopeAA.serialize(transaction, {
281
+ signature: SignatureEnvelope.from(signature),
282
+ })
283
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual({
284
+ ...transaction,
285
+ signature: { signature, type: 'secp256k1' },
286
+ })
287
+ })
288
+
289
+ test('p256', () => {
290
+ const privateKey = P256.randomPrivateKey()
291
+ const publicKey = P256.getPublicKey({ privateKey })
292
+ const signature = P256.sign({
293
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
294
+ privateKey,
295
+ })
296
+ const serialized = TransactionEnvelopeAA.serialize(transaction, {
297
+ signature: SignatureEnvelope.from({
298
+ signature,
299
+ publicKey,
300
+ prehash: true,
301
+ }),
302
+ })
303
+ // biome-ignore lint/suspicious/noTsIgnore: _
304
+ // @ts-ignore
305
+ delete signature.yParity
306
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual({
307
+ ...transaction,
308
+ signature: { prehash: true, publicKey, signature, type: 'p256' },
309
+ })
310
+ })
311
+ })
312
+
313
+ test('feePayerSignature null', () => {
314
+ const transaction_feePayer = TransactionEnvelopeAA.from({
315
+ ...transaction,
316
+ feePayerSignature: null,
317
+ })
318
+ const serialized = TransactionEnvelopeAA.serialize(transaction_feePayer)
319
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual(
320
+ transaction_feePayer,
321
+ )
322
+ })
323
+
324
+ test('feePayerSignature with address', () => {
325
+ const serialized = `0x76${Rlp.fromHex([
326
+ Hex.fromNumber(1), // chainId
327
+ Hex.fromNumber(1), // maxPriorityFeePerGas
328
+ Hex.fromNumber(1), // maxFeePerGas
329
+ Hex.fromNumber(1), // gas
330
+ [
331
+ [
332
+ '0x0000000000000000000000000000000000000000', // to
333
+ Hex.fromNumber(0), // value
334
+ '0x', // data
335
+ ],
336
+ ], // calls
337
+ '0x', // accessList
338
+ Hex.fromNumber(0), // nonceKey
339
+ Hex.fromNumber(0), // nonce
340
+ '0x', // validBefore
341
+ '0x', // validAfter
342
+ '0x', // feeToken
343
+ '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // feePayerSignatureOrSender (address)
344
+ ]).slice(2)}` as const
345
+ const deserialized = TransactionEnvelopeAA.deserialize(serialized)
346
+ expect(deserialized.feePayerSignature).toBe(null)
347
+ })
348
+
349
+ test('feePayerSignature with signature tuple', () => {
350
+ const serialized = `0x76${Rlp.fromHex([
351
+ Hex.fromNumber(1), // chainId
352
+ Hex.fromNumber(1), // maxPriorityFeePerGas
353
+ Hex.fromNumber(1), // maxFeePerGas
354
+ Hex.fromNumber(1), // gas
355
+ [
356
+ [
357
+ '0x0000000000000000000000000000000000000000', // to
358
+ Hex.fromNumber(0), // value
359
+ '0x', // data
360
+ ],
361
+ ], // calls
362
+ '0x', // accessList
363
+ Hex.fromNumber(0), // nonceKey
364
+ Hex.fromNumber(0), // nonce
365
+ '0x', // validBefore
366
+ '0x', // validAfter
367
+ '0x', // feeToken
368
+ [Hex.fromNumber(0), Hex.fromNumber(1), Hex.fromNumber(2)], // feePayerSignatureOrSender (signature tuple)
369
+ ]).slice(2)}` as const
370
+ const deserialized = TransactionEnvelopeAA.deserialize(serialized)
371
+ expect(deserialized.feePayerSignature).toEqual({
372
+ yParity: 0,
373
+ r: 1n,
374
+ s: 2n,
375
+ })
376
+ })
377
+
378
+ describe('raw', () => {
379
+ test('default', () => {
380
+ const serialized = `0x76${Rlp.fromHex([
381
+ Hex.fromNumber(1), // chainId
382
+ Hex.fromNumber(1), // maxPriorityFeePerGas
383
+ Hex.fromNumber(1), // maxFeePerGas
384
+ Hex.fromNumber(1), // gas
385
+ [
386
+ [
387
+ '0x0000000000000000000000000000000000000000', // to
388
+ Hex.fromNumber(0), // value
389
+ '0x', // data
390
+ ],
391
+ ], // calls
392
+ '0x', // accessList
393
+ Hex.fromNumber(0), // nonceKey
394
+ Hex.fromNumber(0), // nonce
395
+ '0x', // validBefore
396
+ '0x', // validAfter
397
+ '0x', // feeToken
398
+ '0x', // feePayerSignature
399
+ ]).slice(2)}` as const
400
+ expect(
401
+ TransactionEnvelopeAA.deserialize(serialized),
402
+ ).toMatchInlineSnapshot(`
403
+ {
404
+ "calls": [
405
+ {
406
+ "to": "0x0000000000000000000000000000000000000000",
407
+ "value": 0n,
408
+ },
409
+ ],
410
+ "chainId": 1,
411
+ "gas": 1n,
412
+ "maxFeePerGas": 1n,
413
+ "maxPriorityFeePerGas": 1n,
414
+ "nonce": 0n,
415
+ "nonceKey": 0n,
416
+ "type": "aa",
417
+ }
418
+ `)
419
+ })
420
+
421
+ test('empty sig', () => {
422
+ const serialized = `0x76${Rlp.fromHex([
423
+ Hex.fromNumber(1), // chainId
424
+ Hex.fromNumber(1), // maxPriorityFeePerGas
425
+ Hex.fromNumber(1), // maxFeePerGas
426
+ Hex.fromNumber(1), // gas
427
+ [
428
+ [
429
+ '0x0000000000000000000000000000000000000000', // to
430
+ Hex.fromNumber(0), // value
431
+ '0x', // data
432
+ ],
433
+ ], // calls
434
+ '0x', // accessList
435
+ Hex.fromNumber(0), // nonceKey
436
+ Hex.fromNumber(0), // nonce
437
+ '0x', // validBefore
438
+ '0x', // validAfter
439
+ '0x', // feeToken
440
+ '0x', // feePayerSignature
441
+ ]).slice(2)}` as const
442
+ expect(
443
+ TransactionEnvelopeAA.deserialize(serialized),
444
+ ).toMatchInlineSnapshot(`
445
+ {
446
+ "calls": [
447
+ {
448
+ "to": "0x0000000000000000000000000000000000000000",
449
+ "value": 0n,
450
+ },
451
+ ],
452
+ "chainId": 1,
453
+ "gas": 1n,
454
+ "maxFeePerGas": 1n,
455
+ "maxPriorityFeePerGas": 1n,
456
+ "nonce": 0n,
457
+ "nonceKey": 0n,
458
+ "type": "aa",
459
+ }
460
+ `)
461
+ })
462
+ })
463
+
464
+ describe('errors', () => {
465
+ test('invalid transaction (all missing)', () => {
466
+ expect(() =>
467
+ TransactionEnvelopeAA.deserialize(`0x76${Rlp.fromHex([]).slice(2)}`),
468
+ ).toThrowErrorMatchingInlineSnapshot(`
469
+ [TransactionEnvelope.InvalidSerializedError: Invalid serialized transaction of type "aa" was provided.
470
+
471
+ Serialized Transaction: "0x76c0"
472
+ Missing Attributes: chainId, maxPriorityFeePerGas, maxFeePerGas, gas, calls, accessList, nonceKey, nonce, validBefore, validAfter, feeToken, feePayerSignatureOrSender]
473
+ `)
474
+ })
475
+
476
+ test('invalid transaction (some missing)', () => {
477
+ expect(() =>
478
+ TransactionEnvelopeAA.deserialize(
479
+ `0x76${Rlp.fromHex(['0x00', '0x01']).slice(2)}`,
480
+ ),
481
+ ).toThrowErrorMatchingInlineSnapshot(`
482
+ [TransactionEnvelope.InvalidSerializedError: Invalid serialized transaction of type "aa" was provided.
483
+
484
+ Serialized Transaction: "0x76c20001"
485
+ Missing Attributes: maxFeePerGas, gas, calls, accessList, nonceKey, nonce, validBefore, validAfter, feeToken, feePayerSignatureOrSender]
486
+ `)
487
+ })
488
+
489
+ test('invalid transaction (empty calls)', () => {
490
+ expect(() =>
491
+ TransactionEnvelopeAA.deserialize(
492
+ `0x76${Rlp.fromHex([
493
+ Hex.fromNumber(1), // chainId
494
+ Hex.fromNumber(1), // maxPriorityFeePerGas
495
+ Hex.fromNumber(1), // maxFeePerGas
496
+ Hex.fromNumber(1), // gas
497
+ [], // calls (empty)
498
+ '0x', // accessList
499
+ Hex.fromNumber(0), // nonceKey
500
+ Hex.fromNumber(0), // nonce
501
+ '0x', // validBefore
502
+ '0x', // validAfter
503
+ '0x', // feeToken
504
+ '0x', // feePayerSignature
505
+ ]).slice(2)}`,
506
+ ),
507
+ ).toThrowErrorMatchingInlineSnapshot(
508
+ `[TransactionEnvelopeAA.CallsEmptyError: Calls list cannot be empty.]`,
509
+ )
510
+ })
511
+
512
+ test('invalid transaction (too many fields with signature)', () => {
513
+ expect(() =>
514
+ TransactionEnvelopeAA.deserialize(
515
+ `0x76${Rlp.fromHex([
516
+ Hex.fromNumber(1), // chainId
517
+ Hex.fromNumber(1), // maxPriorityFeePerGas
518
+ Hex.fromNumber(1), // maxFeePerGas
519
+ Hex.fromNumber(1), // gas
520
+ [
521
+ [
522
+ '0x0000000000000000000000000000000000000000',
523
+ Hex.fromNumber(0),
524
+ '0x',
525
+ ],
526
+ ], // calls
527
+ '0x', // accessList
528
+ Hex.fromNumber(0), // nonceKey
529
+ Hex.fromNumber(0), // nonce
530
+ '0x', // validBefore
531
+ '0x', // validAfter
532
+ '0x', // feeToken
533
+ '0x', // feePayerSignature
534
+ '0x1234', // signature
535
+ '0x5678', // extra field
536
+ ]).slice(2)}`,
537
+ ),
538
+ ).toThrowErrorMatchingInlineSnapshot(`
539
+ [TransactionEnvelope.InvalidSerializedError: Invalid serialized transaction of type "aa" was provided.
540
+
541
+ Serialized Transaction: "0x76ea01010101d8d7940000000000000000000000000000000000000000008080000080808080821234825678"]
542
+ `)
543
+ })
544
+ })
545
+ })
546
+
547
+ describe('from', () => {
548
+ test('default', () => {
549
+ {
550
+ const envelope = TransactionEnvelopeAA.from({
551
+ chainId: 1,
552
+ calls: [{}],
553
+ nonce: 0n,
554
+ nonceKey: 0n,
555
+ })
556
+ expect(envelope).toMatchInlineSnapshot(`
557
+ {
558
+ "calls": [
559
+ {},
560
+ ],
561
+ "chainId": 1,
562
+ "nonce": 0n,
563
+ "nonceKey": 0n,
564
+ "type": "aa",
565
+ }
566
+ `)
567
+ const serialized = TransactionEnvelopeAA.serialize(envelope)
568
+ const envelope2 = TransactionEnvelopeAA.from(serialized)
569
+ expect(envelope2).toEqual(envelope)
570
+ }
571
+
572
+ {
573
+ const envelope = TransactionEnvelopeAA.from({
574
+ chainId: 1,
575
+ calls: [{ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8' }],
576
+ nonce: 0n,
577
+ nonceKey: 0n,
578
+ signature: SignatureEnvelope.from({
579
+ r: 0n,
580
+ s: 1n,
581
+ yParity: 0,
582
+ }),
583
+ })
584
+ expect(envelope).toMatchInlineSnapshot(`
585
+ {
586
+ "calls": [
587
+ {
588
+ "to": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
589
+ },
590
+ ],
591
+ "chainId": 1,
592
+ "nonce": 0n,
593
+ "nonceKey": 0n,
594
+ "signature": {
595
+ "signature": {
596
+ "r": 0n,
597
+ "s": 1n,
598
+ "yParity": 0,
599
+ },
600
+ "type": "secp256k1",
601
+ },
602
+ "type": "aa",
603
+ }
604
+ `)
605
+ const serialized = TransactionEnvelopeAA.serialize(envelope)
606
+ const envelope2 = TransactionEnvelopeAA.from(serialized)
607
+ expect(envelope2).toEqual({
608
+ ...envelope,
609
+ signature: { ...envelope.signature, type: 'secp256k1' },
610
+ })
611
+ }
612
+ })
613
+
614
+ test('options: signature', () => {
615
+ const envelope = TransactionEnvelopeAA.from(
616
+ {
617
+ chainId: 1,
618
+ calls: [{}],
619
+ nonce: 0n,
620
+ nonceKey: 0n,
621
+ },
622
+ {
623
+ signature: SignatureEnvelope.from({
624
+ r: 0n,
625
+ s: 1n,
626
+ yParity: 0,
627
+ }),
628
+ },
629
+ )
630
+ expect(envelope).toMatchInlineSnapshot(`
631
+ {
632
+ "calls": [
633
+ {},
634
+ ],
635
+ "chainId": 1,
636
+ "nonce": 0n,
637
+ "nonceKey": 0n,
638
+ "signature": {
639
+ "signature": {
640
+ "r": 0n,
641
+ "s": 1n,
642
+ "yParity": 0,
643
+ },
644
+ "type": "secp256k1",
645
+ },
646
+ "type": "aa",
647
+ }
648
+ `)
649
+ const serialized = TransactionEnvelopeAA.serialize(envelope)
650
+ const envelope2 = TransactionEnvelopeAA.from(serialized)
651
+ expect(envelope2).toEqual(envelope)
652
+ })
653
+
654
+ test('options: feePayerSignature', () => {
655
+ const envelope = TransactionEnvelopeAA.from(
656
+ {
657
+ chainId: 1,
658
+ calls: [{}],
659
+ nonce: 0n,
660
+ r: 1n,
661
+ s: 2n,
662
+ yParity: 0,
663
+ },
664
+ {
665
+ feePayerSignature: {
666
+ r: 0n,
667
+ s: 1n,
668
+ yParity: 0,
669
+ },
670
+ },
671
+ )
672
+ expect(envelope).toMatchInlineSnapshot(`
673
+ {
674
+ "calls": [
675
+ {},
676
+ ],
677
+ "chainId": 1,
678
+ "feePayerSignature": {
679
+ "r": 0n,
680
+ "s": 1n,
681
+ "yParity": 0,
682
+ },
683
+ "nonce": 0n,
684
+ "r": 1n,
685
+ "s": 2n,
686
+ "type": "aa",
687
+ "yParity": 0,
688
+ }
689
+ `)
690
+ })
691
+
692
+ test('options: feePayerSignature (null)', () => {
693
+ const envelope = TransactionEnvelopeAA.from(
694
+ {
695
+ chainId: 1,
696
+ calls: [{}],
697
+ nonce: 0n,
698
+ },
699
+ {
700
+ feePayerSignature: null,
701
+ },
702
+ )
703
+ expect(envelope).toMatchInlineSnapshot(`
704
+ {
705
+ "calls": [
706
+ {},
707
+ ],
708
+ "chainId": 1,
709
+ "nonce": 0n,
710
+ "type": "aa",
711
+ }
712
+ `)
713
+ })
714
+ })
715
+
716
+ describe('serialize', () => {
717
+ test('default', () => {
718
+ const transaction = TransactionEnvelopeAA.from({
719
+ chainId: 1,
720
+ calls: [
721
+ {
722
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
723
+ value: Value.fromEther('1'),
724
+ },
725
+ ],
726
+ nonce: 785n,
727
+ maxFeePerGas: Value.fromGwei('2'),
728
+ maxPriorityFeePerGas: Value.fromGwei('2'),
729
+ })
730
+ expect(TransactionEnvelopeAA.serialize(transaction)).toMatchInlineSnapshot(
731
+ `"0x76f6018477359400847735940080e0df9470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c08082031180808080"`,
732
+ )
733
+ })
734
+
735
+ test('minimal', () => {
736
+ const transaction = TransactionEnvelopeAA.from({
737
+ chainId: 1,
738
+ calls: [{}],
739
+ nonce: 0n,
740
+ })
741
+ expect(TransactionEnvelopeAA.serialize(transaction)).toMatchInlineSnapshot(
742
+ `"0x76d001808080c4c3808080c0808080808080"`,
743
+ )
744
+ })
745
+
746
+ test('undefined nonceKey', () => {
747
+ const transaction = TransactionEnvelopeAA.from({
748
+ chainId: 1,
749
+ calls: [{}],
750
+ nonce: 0n,
751
+ nonceKey: undefined,
752
+ })
753
+ const serialized = TransactionEnvelopeAA.serialize(transaction)
754
+ expect(serialized).toMatchInlineSnapshot(
755
+ `"0x76d001808080c4c3808080c0808080808080"`,
756
+ )
757
+ })
758
+
759
+ test('multiple calls', () => {
760
+ const transaction = TransactionEnvelopeAA.from({
761
+ chainId: 1,
762
+ calls: [
763
+ {
764
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
765
+ value: Value.fromEther('1'),
766
+ },
767
+ {
768
+ to: '0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc',
769
+ value: Value.fromEther('2'),
770
+ data: '0x1234',
771
+ },
772
+ ],
773
+ nonce: 0n,
774
+ })
775
+ expect(TransactionEnvelopeAA.serialize(transaction)).toMatchInlineSnapshot(
776
+ `"0x76f84f01808080f842df9470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080e1943c44cdddb6a900fa2b585dd299e03d12fa4293bc881bc16d674ec80000821234c0808080808080"`,
777
+ )
778
+ })
779
+
780
+ describe('with signature', () => {
781
+ test('secp256k1', () => {
782
+ const transaction = TransactionEnvelopeAA.from({
783
+ chainId: 1,
784
+ calls: [{ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8' }],
785
+ nonce: 0n,
786
+ })
787
+ const signature = Secp256k1.sign({
788
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
789
+ privateKey,
790
+ })
791
+ expect(
792
+ TransactionEnvelopeAA.serialize(transaction, {
793
+ signature: SignatureEnvelope.from(signature),
794
+ }),
795
+ ).toMatchInlineSnapshot(
796
+ `"0x76f86701808080d8d79470997970c51812dc3a010c7d01b50e0d17dc79c88080c0808080808080b841e333995974d0f82e5dfdb201476c03516d849f1fd3b05db4bb1595dba9ad207827aca889a4780887341008f2d3fac949b145304735ea395b5d68498e80e138be1b"`,
797
+ )
798
+ })
799
+
800
+ test('p256', () => {
801
+ const transaction = TransactionEnvelopeAA.from({
802
+ chainId: 1,
803
+ calls: [{ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8' }],
804
+ nonce: 0n,
805
+ })
806
+ const privateKey = P256.randomPrivateKey()
807
+ const publicKey = P256.getPublicKey({ privateKey })
808
+ const signature = P256.sign({
809
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
810
+ privateKey,
811
+ })
812
+ const serialized = TransactionEnvelopeAA.serialize(transaction, {
813
+ signature: SignatureEnvelope.from({
814
+ signature,
815
+ publicKey,
816
+ prehash: true,
817
+ }),
818
+ })
819
+ // biome-ignore lint/suspicious/noTsIgnore: _
820
+ // @ts-ignore
821
+ delete signature.yParity
822
+ expect(TransactionEnvelopeAA.deserialize(serialized)).toEqual({
823
+ ...transaction,
824
+ nonceKey: 0n,
825
+ signature: { prehash: true, publicKey, signature, type: 'p256' },
826
+ })
827
+ })
828
+ })
829
+
830
+ test('with feePayerSignature', () => {
831
+ const transaction = TransactionEnvelopeAA.from({
832
+ chainId: 1,
833
+ calls: [{ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8' }],
834
+ nonce: 0n,
835
+ })
836
+ expect(
837
+ TransactionEnvelopeAA.serialize(transaction, {
838
+ feePayerSignature: {
839
+ r: 1n,
840
+ s: 2n,
841
+ yParity: 0,
842
+ },
843
+ }),
844
+ ).toMatchInlineSnapshot(
845
+ `"0x76e701808080d8d79470997970c51812dc3a010c7d01b50e0d17dc79c88080c08080808080c3800102"`,
846
+ )
847
+ })
848
+
849
+ test('with feePayerSignature (null)', () => {
850
+ const transaction = TransactionEnvelopeAA.from({
851
+ chainId: 1,
852
+ calls: [{ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8' }],
853
+ nonce: 0n,
854
+ })
855
+ expect(
856
+ TransactionEnvelopeAA.serialize(transaction, {
857
+ feePayerSignature: null,
858
+ }),
859
+ ).toMatchInlineSnapshot(
860
+ `"0x76e401808080d8d79470997970c51812dc3a010c7d01b50e0d17dc79c88080c0808080808000"`,
861
+ )
862
+ })
863
+
864
+ test('format: feePayer', () => {
865
+ const transaction = TransactionEnvelopeAA.from({
866
+ chainId: 1,
867
+ calls: [{ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8' }],
868
+ nonce: 0n,
869
+ })
870
+ expect(
871
+ TransactionEnvelopeAA.serialize(transaction, {
872
+ sender: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
873
+ format: 'feePayer',
874
+ }),
875
+ ).toMatchInlineSnapshot(
876
+ `"0x78f83801808080d8d79470997970c51812dc3a010c7d01b50e0d17dc79c88080c0808080808094f39fd6e51aad88f6f4ce6ab8827279cfffb92266"`,
877
+ )
878
+ })
879
+ })
880
+
881
+ describe('hash', () => {
882
+ describe('default', () => {
883
+ test('secp256k1', () => {
884
+ const transaction = TransactionEnvelopeAA.from({
885
+ chainId: 1,
886
+ calls: [
887
+ {
888
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
889
+ value: Value.fromEther('1'),
890
+ },
891
+ ],
892
+ nonce: 0n,
893
+ })
894
+ const signature = Secp256k1.sign({
895
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
896
+ privateKey,
897
+ })
898
+ const signed = TransactionEnvelopeAA.from(transaction, {
899
+ signature: SignatureEnvelope.from(signature),
900
+ })
901
+ expect(TransactionEnvelopeAA.hash(signed)).toMatchInlineSnapshot(
902
+ `"0x3f46e9635e9a55ceb7c4efa5a652227446c392becf1853ca024078974451ba36"`,
903
+ )
904
+ })
905
+ })
906
+
907
+ test('presign', () => {
908
+ const transaction = TransactionEnvelopeAA.from({
909
+ chainId: 1,
910
+ calls: [
911
+ {
912
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
913
+ value: Value.fromEther('1'),
914
+ },
915
+ ],
916
+ nonce: 0n,
917
+ })
918
+ expect(
919
+ TransactionEnvelopeAA.hash(transaction, { presign: true }),
920
+ ).toMatchInlineSnapshot(
921
+ `"0x10470898907327464194b05c9d6cbc6bc6c4dab48e6287898c0600dd231f111d"`,
922
+ )
923
+ })
924
+ })
925
+
926
+ describe('getSignPayload', () => {
927
+ test('default', () => {
928
+ const transaction = TransactionEnvelopeAA.from({
929
+ chainId: 1,
930
+ calls: [
931
+ {
932
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
933
+ value: Value.fromEther('1'),
934
+ },
935
+ ],
936
+ nonce: 0n,
937
+ })
938
+ expect(
939
+ TransactionEnvelopeAA.getSignPayload(transaction),
940
+ ).toMatchInlineSnapshot(
941
+ `"0x10470898907327464194b05c9d6cbc6bc6c4dab48e6287898c0600dd231f111d"`,
942
+ )
943
+ })
944
+ })
945
+
946
+ describe('getFeePayerSignPayload', () => {
947
+ test('default', () => {
948
+ const transaction = TransactionEnvelopeAA.from({
949
+ chainId: 1,
950
+ calls: [
951
+ {
952
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
953
+ value: Value.fromEther('1'),
954
+ },
955
+ ],
956
+ nonce: 0n,
957
+ })
958
+ expect(
959
+ TransactionEnvelopeAA.getFeePayerSignPayload(transaction, {
960
+ sender: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
961
+ }),
962
+ ).toMatchInlineSnapshot(
963
+ `"0xaeee7aa3df5d00d3ca8fe76e524f1bc728741f4dfb3e99cbb908d666926a1cf6"`,
964
+ )
965
+ })
966
+
967
+ test('with feeToken', () => {
968
+ const transaction = TransactionEnvelopeAA.from({
969
+ chainId: 1,
970
+ calls: [
971
+ {
972
+ to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
973
+ value: Value.fromEther('1'),
974
+ },
975
+ ],
976
+ nonce: 0n,
977
+ feeToken: '0x20c0000000000000000000000000000000000000',
978
+ })
979
+ const hash1 = TransactionEnvelopeAA.getFeePayerSignPayload(transaction, {
980
+ sender: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
981
+ })
982
+
983
+ // Change feeToken - hash should be different
984
+ const transaction2 = TransactionEnvelopeAA.from({
985
+ ...transaction,
986
+ feeToken: '0x20c0000000000000000000000000000000000001',
987
+ })
988
+ const hash2 = TransactionEnvelopeAA.getFeePayerSignPayload(transaction2, {
989
+ sender: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
990
+ })
991
+
992
+ expect(hash1).not.toBe(hash2)
993
+ })
994
+ })
995
+
996
+ describe('validate', () => {
997
+ test('valid', () => {
998
+ expect(
999
+ TransactionEnvelopeAA.validate({
1000
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
1001
+ chainId: 1,
1002
+ }),
1003
+ ).toBe(true)
1004
+ })
1005
+
1006
+ test('invalid (empty calls)', () => {
1007
+ expect(
1008
+ TransactionEnvelopeAA.validate({
1009
+ calls: [],
1010
+ chainId: 1,
1011
+ }),
1012
+ ).toBe(false)
1013
+ })
1014
+
1015
+ test('invalid (validity window)', () => {
1016
+ expect(
1017
+ TransactionEnvelopeAA.validate({
1018
+ calls: [{ to: '0x0000000000000000000000000000000000000000' }],
1019
+ chainId: 1,
1020
+ validBefore: 100,
1021
+ validAfter: 200,
1022
+ }),
1023
+ ).toBe(false)
1024
+ })
1025
+ })
1026
+
1027
+ describe('e2e', () => {
1028
+ const node = Instance.tempo({ port: 3000 })
1029
+ beforeEach(() => node.start())
1030
+ afterEach(() => node.stop())
1031
+
1032
+ test('behavior: default (secp256k1)', async () => {
1033
+ const address = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
1034
+ const privateKey =
1035
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
1036
+
1037
+ const transport = RpcTransport.fromHttp('http://localhost:3000')
1038
+
1039
+ const nonce = await transport.request({
1040
+ method: 'eth_getTransactionCount',
1041
+ params: [address, 'pending'],
1042
+ })
1043
+
1044
+ const transaction = TransactionEnvelopeAA.from({
1045
+ calls: [
1046
+ {
1047
+ to: '0x0000000000000000000000000000000000000000',
1048
+ value: Value.fromEther('1'),
1049
+ },
1050
+ ],
1051
+ chainId: 1337,
1052
+ feeToken: '0x20c0000000000000000000000000000000000001',
1053
+ nonce: BigInt(nonce),
1054
+ gas: 100_000n,
1055
+ maxFeePerGas: Value.fromGwei('20'),
1056
+ maxPriorityFeePerGas: Value.fromGwei('10'),
1057
+ })
1058
+
1059
+ const signature = Secp256k1.sign({
1060
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
1061
+ privateKey,
1062
+ })
1063
+
1064
+ const serialized_signed = TransactionEnvelopeAA.serialize(transaction, {
1065
+ signature: SignatureEnvelope.from(signature),
1066
+ })
1067
+
1068
+ const receipt = await transport.request({
1069
+ method: 'eth_sendRawTransactionSync',
1070
+ params: [serialized_signed],
1071
+ })
1072
+
1073
+ expect(receipt).toBeDefined()
1074
+
1075
+ {
1076
+ const response = await transport.request({
1077
+ method: 'eth_getTransactionByHash',
1078
+ params: [receipt.transactionHash],
1079
+ })
1080
+ if (!response) throw new Error()
1081
+
1082
+ const { blockNumber, blockHash, ...rest } = response
1083
+
1084
+ expect(blockNumber).toBeDefined()
1085
+ expect(blockHash).toBeDefined()
1086
+ expect(rest).toMatchInlineSnapshot(`
1087
+ {
1088
+ "accessList": [],
1089
+ "calls": [
1090
+ {
1091
+ "input": "0x",
1092
+ "to": "0x0000000000000000000000000000000000000000",
1093
+ "value": "0xde0b6b3a7640000",
1094
+ },
1095
+ ],
1096
+ "chainId": "0x539",
1097
+ "feePayerSignature": null,
1098
+ "feeToken": "0x20c0000000000000000000000000000000000001",
1099
+ "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
1100
+ "gas": "0x186a0",
1101
+ "gasPrice": "0x2540be42c",
1102
+ "hash": "0x619a731fb6541ad920821eb1cb11fa0bc718dbd894913d7952be322f6245c98e",
1103
+ "maxFeePerGas": "0x4a817c800",
1104
+ "maxPriorityFeePerGas": "0x2540be400",
1105
+ "nonce": "0x0",
1106
+ "nonceKey": "0x0",
1107
+ "signature": {
1108
+ "r": "0xe43858180a3fb0849348c721682a8610ee0583328f20644c5a20aa51acef479c",
1109
+ "s": "0x3106b71428823fe3f9199d1476605220af5855f1cb1b0483a48a50d7bc36096b",
1110
+ "type": "secp256k1",
1111
+ "v": "0x1",
1112
+ "yParity": "0x1",
1113
+ },
1114
+ "transactionIndex": "0x0",
1115
+ "type": "0x76",
1116
+ "validAfter": null,
1117
+ "validBefore": null,
1118
+ }
1119
+ `)
1120
+ }
1121
+
1122
+ const { blockNumber, blockHash, ...rest } = receipt
1123
+
1124
+ expect(blockNumber).toBeDefined()
1125
+ expect(blockHash).toBeDefined()
1126
+ expect(rest).toMatchInlineSnapshot(`
1127
+ {
1128
+ "contractAddress": null,
1129
+ "cumulativeGasUsed": "0x5208",
1130
+ "effectiveGasPrice": "0x2540be42c",
1131
+ "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
1132
+ "gasUsed": "0x5208",
1133
+ "logs": [],
1134
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1135
+ "status": "0x0",
1136
+ "to": "0x0000000000000000000000000000000000000000",
1137
+ "transactionHash": "0x619a731fb6541ad920821eb1cb11fa0bc718dbd894913d7952be322f6245c98e",
1138
+ "transactionIndex": "0x0",
1139
+ "type": "0x76",
1140
+ }
1141
+ `)
1142
+ })
1143
+
1144
+ test('behavior: default (p256)', async () => {
1145
+ const privateKey =
1146
+ '0x062d199fd1d30c4a905ed1164a31e73759a13827687a2f3057a7d19c220bc933'
1147
+ const publicKey = P256.getPublicKey({ privateKey })
1148
+ const address = Address.fromPublicKey(publicKey)
1149
+
1150
+ const client = createClient({
1151
+ account: privateKeyToAccount(
1152
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
1153
+ ),
1154
+ chain: tempoLocal,
1155
+ transport: http('http://localhost:3000'),
1156
+ })
1157
+
1158
+ await Actions.token.transferSync(client, {
1159
+ amount: parseEther('10000'),
1160
+ to: address,
1161
+ })
1162
+
1163
+ const transaction = TransactionEnvelopeAA.from({
1164
+ calls: [
1165
+ {
1166
+ to: '0x0000000000000000000000000000000000000000',
1167
+ value: Value.fromEther('1'),
1168
+ },
1169
+ ],
1170
+ chainId: 1337,
1171
+ gas: 100_000n,
1172
+ maxFeePerGas: Value.fromGwei('20'),
1173
+ maxPriorityFeePerGas: Value.fromGwei('10'),
1174
+ })
1175
+
1176
+ const signature = P256.sign({
1177
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
1178
+ privateKey,
1179
+ hash: false,
1180
+ })
1181
+
1182
+ const serialized_signed = TransactionEnvelopeAA.serialize(transaction, {
1183
+ signature: SignatureEnvelope.from({
1184
+ signature,
1185
+ publicKey,
1186
+ prehash: false,
1187
+ }),
1188
+ })
1189
+
1190
+ const receipt = await client.request({
1191
+ method: 'eth_sendRawTransactionSync',
1192
+ params: [serialized_signed],
1193
+ })
1194
+
1195
+ expect(receipt).toBeDefined()
1196
+
1197
+ {
1198
+ const response = await client.request({
1199
+ method: 'eth_getTransactionByHash',
1200
+ params: [receipt.transactionHash],
1201
+ })
1202
+ if (!response) throw new Error()
1203
+
1204
+ const { blockNumber, blockHash, ...rest } = response
1205
+
1206
+ expect(blockNumber).toBeDefined()
1207
+ expect(blockHash).toBeDefined()
1208
+ expect(rest).toMatchInlineSnapshot(`
1209
+ {
1210
+ "accessList": [],
1211
+ "calls": [
1212
+ {
1213
+ "input": "0x",
1214
+ "to": "0x0000000000000000000000000000000000000000",
1215
+ "value": "0xde0b6b3a7640000",
1216
+ },
1217
+ ],
1218
+ "chainId": "0x539",
1219
+ "feePayerSignature": null,
1220
+ "feeToken": null,
1221
+ "from": "0x6472aeab3269f4165775753156702c06ccc70f8b",
1222
+ "gas": "0x186a0",
1223
+ "gasPrice": "0x2540be42c",
1224
+ "hash": "0x6555ebf80163ff84929f864a281fd475685c15279b516233035d4a243f427bfe",
1225
+ "maxFeePerGas": "0x4a817c800",
1226
+ "maxPriorityFeePerGas": "0x2540be400",
1227
+ "nonce": "0x0",
1228
+ "nonceKey": "0x0",
1229
+ "signature": {
1230
+ "preHash": false,
1231
+ "pubKeyX": "0xecbf69146add5d7c649c96d90b64d90702c6faae7115adbad50e5e61b2c5f40d",
1232
+ "pubKeyY": "0xeca3a5fc6dc4225b4f3f9720750651d43c6eb45c0492b8e9930394d1524784c6",
1233
+ "r": "0x78de783595944c23338512ed47edac09c3908e6fdbcd1283cebd86ddb24f160f",
1234
+ "s": "0x442099a953b4db06ae2eaa901c29979cbda1f126169c99e534855c4691c220ca",
1235
+ "type": "p256",
1236
+ },
1237
+ "transactionIndex": "0x0",
1238
+ "type": "0x76",
1239
+ "validAfter": null,
1240
+ "validBefore": null,
1241
+ }
1242
+ `)
1243
+ }
1244
+
1245
+ const { blockNumber, blockHash, ...rest } = receipt
1246
+
1247
+ expect(blockNumber).toBeDefined()
1248
+ expect(blockHash).toBeDefined()
1249
+ expect(rest).toMatchInlineSnapshot(`
1250
+ {
1251
+ "contractAddress": null,
1252
+ "cumulativeGasUsed": "0x6590",
1253
+ "effectiveGasPrice": "0x2540be42c",
1254
+ "from": "0x6472aeab3269f4165775753156702c06ccc70f8b",
1255
+ "gasUsed": "0x6590",
1256
+ "logs": [],
1257
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1258
+ "status": "0x0",
1259
+ "to": "0x0000000000000000000000000000000000000000",
1260
+ "transactionHash": "0x6555ebf80163ff84929f864a281fd475685c15279b516233035d4a243f427bfe",
1261
+ "transactionIndex": "0x0",
1262
+ "type": "0x76",
1263
+ }
1264
+ `)
1265
+ })
1266
+
1267
+ test('behavior: default (webauthn)', async () => {
1268
+ const privateKey =
1269
+ '0x062d199fd1d30c4a905ed1164a31e73759a13827687a2f3057a7d19c220bc933'
1270
+ const publicKey = P256.getPublicKey({ privateKey })
1271
+ const address = Address.fromPublicKey(publicKey)
1272
+
1273
+ const client = createClient({
1274
+ account: privateKeyToAccount(
1275
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
1276
+ ),
1277
+ chain: tempoLocal,
1278
+ transport: http('http://localhost:3000'),
1279
+ })
1280
+
1281
+ await Actions.token.transferSync(client, {
1282
+ amount: parseEther('10000'),
1283
+ to: address,
1284
+ })
1285
+
1286
+ const transaction = TransactionEnvelopeAA.from({
1287
+ calls: [
1288
+ {
1289
+ to: '0x0000000000000000000000000000000000000000',
1290
+ value: Value.fromEther('1'),
1291
+ },
1292
+ ],
1293
+ chainId: 1337,
1294
+ gas: 100_000n,
1295
+ maxFeePerGas: Value.fromGwei('20'),
1296
+ maxPriorityFeePerGas: Value.fromGwei('10'),
1297
+ })
1298
+
1299
+ const { metadata, payload } = WebAuthnP256.getSignPayload({
1300
+ challenge: TransactionEnvelopeAA.getSignPayload(transaction),
1301
+ rpId: 'localhost',
1302
+ origin: 'http://localhost',
1303
+ })
1304
+
1305
+ const signature = P256.sign({
1306
+ payload,
1307
+ privateKey,
1308
+ hash: true,
1309
+ })
1310
+
1311
+ const serialized_signed = TransactionEnvelopeAA.serialize(transaction, {
1312
+ signature: SignatureEnvelope.from({
1313
+ signature,
1314
+ publicKey,
1315
+ metadata,
1316
+ }),
1317
+ })
1318
+
1319
+ const receipt = await client.request({
1320
+ method: 'eth_sendRawTransactionSync',
1321
+ params: [serialized_signed],
1322
+ })
1323
+
1324
+ expect(receipt).toBeDefined()
1325
+
1326
+ {
1327
+ const response = await client.request({
1328
+ method: 'eth_getTransactionByHash',
1329
+ params: [receipt.transactionHash],
1330
+ })
1331
+ if (!response) throw new Error()
1332
+
1333
+ const { blockNumber, blockHash, ...rest } = response
1334
+
1335
+ expect(blockNumber).toBeDefined()
1336
+ expect(blockHash).toBeDefined()
1337
+ expect(rest).toMatchInlineSnapshot(`
1338
+ {
1339
+ "accessList": [],
1340
+ "calls": [
1341
+ {
1342
+ "input": "0x",
1343
+ "to": "0x0000000000000000000000000000000000000000",
1344
+ "value": "0xde0b6b3a7640000",
1345
+ },
1346
+ ],
1347
+ "chainId": "0x539",
1348
+ "feePayerSignature": null,
1349
+ "feeToken": null,
1350
+ "from": "0x6472aeab3269f4165775753156702c06ccc70f8b",
1351
+ "gas": "0x186a0",
1352
+ "gasPrice": "0x2540be42c",
1353
+ "hash": "0x69f56d391d297b45ce3767fa803c93b14ceb1662db67b3822795da9032dab925",
1354
+ "maxFeePerGas": "0x4a817c800",
1355
+ "maxPriorityFeePerGas": "0x2540be400",
1356
+ "nonce": "0x0",
1357
+ "nonceKey": "0x0",
1358
+ "signature": {
1359
+ "pubKeyX": "0xecbf69146add5d7c649c96d90b64d90702c6faae7115adbad50e5e61b2c5f40d",
1360
+ "pubKeyY": "0xeca3a5fc6dc4225b4f3f9720750651d43c6eb45c0492b8e9930394d1524784c6",
1361
+ "r": "0x85ab9affd4d7f867f4cc7c4a89995ddeab77c803cf201a22d4797a23852bde22",
1362
+ "s": "0x451d76d4db09f1ab6a635d46eaece7bd006c0dc67d750830d4154fbee599dcc1",
1363
+ "type": "webAuthn",
1364
+ "webauthnData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a225a7275684846506271366434384f646c4f326658574c52697456457739674d5944594f6141704333744538222c226f726967696e223a22687474703a2f2f6c6f63616c686f7374222c2263726f73734f726967696e223a66616c73657d",
1365
+ },
1366
+ "transactionIndex": "0x0",
1367
+ "type": "0x76",
1368
+ "validAfter": null,
1369
+ "validBefore": null,
1370
+ }
1371
+ `)
1372
+ }
1373
+
1374
+ const { blockNumber, blockHash, ...rest } = receipt
1375
+
1376
+ expect(blockNumber).toBeDefined()
1377
+ expect(blockHash).toBeDefined()
1378
+ expect(rest).toMatchInlineSnapshot(`
1379
+ {
1380
+ "contractAddress": null,
1381
+ "cumulativeGasUsed": "0x6fc0",
1382
+ "effectiveGasPrice": "0x2540be42c",
1383
+ "from": "0x6472aeab3269f4165775753156702c06ccc70f8b",
1384
+ "gasUsed": "0x6fc0",
1385
+ "logs": [],
1386
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1387
+ "status": "0x0",
1388
+ "to": "0x0000000000000000000000000000000000000000",
1389
+ "transactionHash": "0x69f56d391d297b45ce3767fa803c93b14ceb1662db67b3822795da9032dab925",
1390
+ "transactionIndex": "0x0",
1391
+ "type": "0x76",
1392
+ }
1393
+ `)
1394
+ })
1395
+
1396
+ test('behavior: feePayerSignature (user → feePayer)', async () => {
1397
+ const feePayer = {
1398
+ address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
1399
+ privateKey:
1400
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
1401
+ } as const
1402
+ const sender = {
1403
+ address: '0x0a275bEE91B39092Dfd57089Dee0EB0539020B90',
1404
+ privateKey:
1405
+ '0xfe24691eff5297c76e847dc78a8966b96cf65a44140b9a0d3f5100ce71d74a59',
1406
+ } as const
1407
+
1408
+ const transport = RpcTransport.fromHttp('http://localhost:3000')
1409
+
1410
+ const nonce = await transport.request({
1411
+ method: 'eth_getTransactionCount',
1412
+ params: [sender.address, 'pending'],
1413
+ })
1414
+
1415
+ const transaction = TransactionEnvelopeAA.from({
1416
+ calls: [{ to: '0x0000000000000000000000000000000000000000', value: 0n }],
1417
+ chainId: 1337,
1418
+ feePayerSignature: null,
1419
+ nonce: BigInt(nonce),
1420
+ gas: 100000n,
1421
+ maxFeePerGas: Hex.toBigInt('0x2c'),
1422
+ maxPriorityFeePerGas: Hex.toBigInt('0x2c'),
1423
+ })
1424
+
1425
+ const signature = Secp256k1.sign({
1426
+ payload: TransactionEnvelopeAA.getSignPayload(transaction),
1427
+ // unfunded PK
1428
+ privateKey: sender.privateKey,
1429
+ })
1430
+
1431
+ const transaction_signed = TransactionEnvelopeAA.from(transaction, {
1432
+ signature: SignatureEnvelope.from(signature),
1433
+ })
1434
+
1435
+ const feePayerSignature = Secp256k1.sign({
1436
+ payload: TransactionEnvelopeAA.getFeePayerSignPayload(
1437
+ transaction_signed,
1438
+ { sender: sender.address },
1439
+ ),
1440
+ privateKey: feePayer.privateKey,
1441
+ })
1442
+
1443
+ const serialized_signed = TransactionEnvelopeAA.serialize(
1444
+ transaction_signed,
1445
+ {
1446
+ feePayerSignature,
1447
+ },
1448
+ )
1449
+
1450
+ const receipt = await transport.request({
1451
+ method: 'eth_sendRawTransactionSync',
1452
+ params: [serialized_signed],
1453
+ })
1454
+
1455
+ const { blockNumber, blockHash, logs, ...rest } = receipt
1456
+
1457
+ expect(blockNumber).toBeDefined()
1458
+ expect(blockHash).toBeDefined()
1459
+ expect(logs).toBeDefined()
1460
+ expect(rest).toMatchInlineSnapshot(`
1461
+ {
1462
+ "contractAddress": null,
1463
+ "cumulativeGasUsed": "0x5208",
1464
+ "effectiveGasPrice": "0x2c",
1465
+ "from": "0x0a275bee91b39092dfd57089dee0eb0539020b90",
1466
+ "gasUsed": "0x5208",
1467
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000008000000000008000000000000000000000000000000000000000000000000000100000000000000000000000000000010000000000000000000000000000000000020000000000000100000000040000000000000000020000000000000000000000000000000000000000000000000000000000000000002000000200000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1468
+ "status": "0x1",
1469
+ "to": "0x0000000000000000000000000000000000000000",
1470
+ "transactionHash": "0x4dfc9ff9ca1613f5598aef948a6582f5b1e703cac2a9c42ff6aee17594e8e410",
1471
+ "transactionIndex": "0x0",
1472
+ "type": "0x76",
1473
+ }
1474
+ `)
1475
+
1476
+ const tx = await transport
1477
+ .request({
1478
+ method: 'eth_getTransactionByHash',
1479
+ params: [receipt.transactionHash],
1480
+ })
1481
+ .then(Transaction.fromRpc)
1482
+
1483
+ expect({
1484
+ ...tx,
1485
+ blockHash: undefined,
1486
+ blockNumber: undefined,
1487
+ }).toMatchInlineSnapshot(`
1488
+ {
1489
+ "accessList": [],
1490
+ "blockHash": undefined,
1491
+ "blockNumber": undefined,
1492
+ "calls": [
1493
+ {
1494
+ "data": "0x",
1495
+ "to": "0x0000000000000000000000000000000000000000",
1496
+ "value": 0n,
1497
+ },
1498
+ ],
1499
+ "chainId": 1337,
1500
+ "data": undefined,
1501
+ "feePayer": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
1502
+ "feePayerSignature": {
1503
+ "r": 43378281592208347441865552210308016112467267198196289074355464650745129225935n,
1504
+ "s": 27085416135574431106158684173224223218527774861914424707575629469330173001812n,
1505
+ "v": 27,
1506
+ "yParity": 0,
1507
+ },
1508
+ "feeToken": null,
1509
+ "from": "0x0a275bee91b39092dfd57089dee0eb0539020b90",
1510
+ "gas": 100000n,
1511
+ "gasPrice": 44n,
1512
+ "hash": "0x4dfc9ff9ca1613f5598aef948a6582f5b1e703cac2a9c42ff6aee17594e8e410",
1513
+ "maxFeePerGas": 44n,
1514
+ "maxPriorityFeePerGas": 44n,
1515
+ "nonce": 0n,
1516
+ "nonceKey": 0n,
1517
+ "signature": {
1518
+ "signature": {
1519
+ "r": 58903572187112378577233587639727517391280428405029588654830213610953355580984n,
1520
+ "s": 37751027942634060522067136615803679123517065498160046803985825017412584342835n,
1521
+ "yParity": 1,
1522
+ },
1523
+ "type": "secp256k1",
1524
+ },
1525
+ "transactionIndex": 0,
1526
+ "type": "aa",
1527
+ "validAfter": null,
1528
+ "validBefore": null,
1529
+ "value": 0n,
1530
+ }
1531
+ `)
1532
+ })
1533
+ })