tempo.ts 0.9.0 → 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 (55) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/ox/AuthorizationTempo.d.ts +450 -0
  3. package/dist/ox/AuthorizationTempo.d.ts.map +1 -0
  4. package/dist/ox/AuthorizationTempo.js +433 -0
  5. package/dist/ox/AuthorizationTempo.js.map +1 -0
  6. package/dist/ox/KeyAuthorization.d.ts +1 -1
  7. package/dist/ox/KeyAuthorization.d.ts.map +1 -1
  8. package/dist/ox/KeyAuthorization.js +3 -4
  9. package/dist/ox/KeyAuthorization.js.map +1 -1
  10. package/dist/ox/Transaction.d.ts +4 -3
  11. package/dist/ox/Transaction.d.ts.map +1 -1
  12. package/dist/ox/Transaction.js +7 -0
  13. package/dist/ox/Transaction.js.map +1 -1
  14. package/dist/ox/TransactionEnvelopeTempo.d.ts +3 -3
  15. package/dist/ox/TransactionEnvelopeTempo.d.ts.map +1 -1
  16. package/dist/ox/TransactionEnvelopeTempo.js +8 -4
  17. package/dist/ox/TransactionEnvelopeTempo.js.map +1 -1
  18. package/dist/ox/TransactionRequest.d.ts +6 -4
  19. package/dist/ox/TransactionRequest.d.ts.map +1 -1
  20. package/dist/ox/TransactionRequest.js +7 -1
  21. package/dist/ox/TransactionRequest.js.map +1 -1
  22. package/dist/ox/index.d.ts +1 -0
  23. package/dist/ox/index.d.ts.map +1 -1
  24. package/dist/ox/index.js +1 -0
  25. package/dist/ox/index.js.map +1 -1
  26. package/dist/viem/Chain.d.ts +8 -3
  27. package/dist/viem/Chain.d.ts.map +1 -1
  28. package/dist/viem/Chain.js +1 -0
  29. package/dist/viem/Chain.js.map +1 -1
  30. package/dist/viem/Formatters.d.ts.map +1 -1
  31. package/dist/viem/Formatters.js +0 -13
  32. package/dist/viem/Formatters.js.map +1 -1
  33. package/dist/viem/Transaction.d.ts +5 -5
  34. package/dist/viem/Transaction.d.ts.map +1 -1
  35. package/dist/viem/Transaction.js +2 -15
  36. package/dist/viem/Transaction.js.map +1 -1
  37. package/dist/wagmi/Connector.d.ts +6 -12
  38. package/dist/wagmi/Connector.d.ts.map +1 -1
  39. package/dist/wagmi/Connector.js +73 -18
  40. package/dist/wagmi/Connector.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/ox/AuthorizationTempo.test.ts +1256 -0
  43. package/src/ox/AuthorizationTempo.ts +648 -0
  44. package/src/ox/KeyAuthorization.ts +5 -7
  45. package/src/ox/Transaction.ts +14 -3
  46. package/src/ox/TransactionEnvelopeTempo.test.ts +172 -2
  47. package/src/ox/TransactionEnvelopeTempo.ts +15 -5
  48. package/src/ox/TransactionRequest.ts +19 -5
  49. package/src/ox/e2e.test.ts +80 -8
  50. package/src/ox/index.ts +1 -0
  51. package/src/viem/Chain.ts +1 -0
  52. package/src/viem/Formatters.ts +0 -13
  53. package/src/viem/Transaction.ts +8 -29
  54. package/src/viem/e2e.test.ts +14 -28
  55. package/src/wagmi/Connector.ts +104 -31
@@ -0,0 +1,1256 @@
1
+ import { P256, Secp256k1 } from 'ox'
2
+ import { describe, expect, expectTypeOf, test } from 'vitest'
3
+ import * as AuthorizationTempo from './AuthorizationTempo.js'
4
+ import * as SignatureEnvelope from './SignatureEnvelope.js'
5
+
6
+ // Use a fixed private key for testing signatures
7
+ const testPrivateKey =
8
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' as const
9
+
10
+ describe('from', () => {
11
+ test('default', () => {
12
+ {
13
+ const authorization = AuthorizationTempo.from({
14
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
15
+ chainId: 1,
16
+ nonce: 40n,
17
+ })
18
+ expectTypeOf(authorization).toEqualTypeOf<{
19
+ readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c'
20
+ readonly chainId: 1
21
+ readonly nonce: 40n
22
+ }>()
23
+ expectTypeOf(authorization).toExtend<
24
+ AuthorizationTempo.AuthorizationTempo<false>
25
+ >()
26
+ expect(authorization).toMatchInlineSnapshot(
27
+ `
28
+ {
29
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
30
+ "chainId": 1,
31
+ "nonce": 40n,
32
+ }
33
+ `,
34
+ )
35
+ }
36
+
37
+ {
38
+ const authorization = AuthorizationTempo.from({
39
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
40
+ chainId: 1,
41
+ nonce: 40n,
42
+ signature: {
43
+ signature: {
44
+ r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
45
+ s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
46
+ yParity: 0,
47
+ },
48
+ type: 'secp256k1' as const,
49
+ },
50
+ })
51
+ expectTypeOf(authorization).toEqualTypeOf<{
52
+ readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c'
53
+ readonly chainId: 1
54
+ readonly nonce: 40n
55
+ readonly signature: {
56
+ readonly signature: {
57
+ readonly r: 49782753348462494199823712700004552394425719014458918871452329774910450607807n
58
+ readonly s: 33726695977844476214676913201140481102225469284307016937915595756355928419768n
59
+ readonly yParity: 0
60
+ }
61
+ readonly type: 'secp256k1'
62
+ }
63
+ }>()
64
+ expectTypeOf(authorization).toExtend<
65
+ AuthorizationTempo.AuthorizationTempo<true>
66
+ >()
67
+ expect(authorization).toMatchInlineSnapshot(
68
+ `
69
+ {
70
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
71
+ "chainId": 1,
72
+ "nonce": 40n,
73
+ "signature": {
74
+ "signature": {
75
+ "r": 49782753348462494199823712700004552394425719014458918871452329774910450607807n,
76
+ "s": 33726695977844476214676913201140481102225469284307016937915595756355928419768n,
77
+ "yParity": 0,
78
+ },
79
+ "type": "secp256k1",
80
+ },
81
+ }
82
+ `,
83
+ )
84
+ }
85
+ })
86
+
87
+ test('options: signature (secp256k1)', () => {
88
+ const authorization = AuthorizationTempo.from({
89
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
90
+ chainId: 1,
91
+ nonce: 40n,
92
+ })
93
+ const signature = Secp256k1.sign({
94
+ payload: AuthorizationTempo.getSignPayload(authorization),
95
+ privateKey: testPrivateKey,
96
+ })
97
+ const signatureEnvelope = SignatureEnvelope.from({
98
+ signature,
99
+ type: 'secp256k1',
100
+ })
101
+ const authorization_signed = AuthorizationTempo.from(authorization, {
102
+ signature: signatureEnvelope,
103
+ })
104
+ expectTypeOf(authorization_signed).toExtend<{
105
+ readonly address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c'
106
+ readonly chainId: 1
107
+ readonly nonce: 40n
108
+ }>()
109
+ expectTypeOf(authorization_signed).toExtend<
110
+ AuthorizationTempo.AuthorizationTempo<true>
111
+ >()
112
+ expect(authorization_signed).toMatchInlineSnapshot(
113
+ `
114
+ {
115
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
116
+ "chainId": 1,
117
+ "nonce": 40n,
118
+ "signature": {
119
+ "signature": {
120
+ "r": 74666311849961653398815470296948700361392062371901161364182304079113687952627n,
121
+ "s": 24912990662134805731506157958890440652926649106845286943280690489391727501383n,
122
+ "yParity": 1,
123
+ },
124
+ "type": "secp256k1",
125
+ },
126
+ }
127
+ `,
128
+ )
129
+ })
130
+
131
+ test('options: signature (p256)', () => {
132
+ const authorization = AuthorizationTempo.from({
133
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
134
+ chainId: 1,
135
+ nonce: 40n,
136
+ })
137
+
138
+ const privateKey = P256.randomPrivateKey()
139
+ const publicKey = P256.getPublicKey({ privateKey })
140
+ const payload = AuthorizationTempo.getSignPayload(authorization)
141
+ const signature = P256.sign({ payload, privateKey })
142
+
143
+ const signatureEnvelope: SignatureEnvelope.P256 = {
144
+ prehash: true,
145
+ publicKey,
146
+ signature,
147
+ type: 'p256',
148
+ }
149
+
150
+ const authorization_signed = AuthorizationTempo.from(authorization, {
151
+ signature: signatureEnvelope,
152
+ })
153
+
154
+ expectTypeOf(authorization_signed).toExtend<
155
+ AuthorizationTempo.AuthorizationTempo<true>
156
+ >()
157
+ expect(authorization_signed.signature.type).toBe('p256')
158
+ expect(authorization_signed.signature.prehash).toBe(true)
159
+ expect(authorization_signed.signature.publicKey).toEqual(publicKey)
160
+ })
161
+
162
+ test('options: signature (webAuthn)', () => {
163
+ const authorization = AuthorizationTempo.from({
164
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
165
+ chainId: 1,
166
+ nonce: 40n,
167
+ })
168
+
169
+ const signatureEnvelope = SignatureEnvelope.from({
170
+ metadata: {
171
+ authenticatorData:
172
+ '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
173
+ clientDataJSON:
174
+ '{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}',
175
+ },
176
+ publicKey: { prefix: 4, x: 1n, y: 2n },
177
+ signature: { r: 3n, s: 4n },
178
+ type: 'webAuthn',
179
+ })
180
+
181
+ const authorization_signed = AuthorizationTempo.from(authorization, {
182
+ signature: signatureEnvelope,
183
+ })
184
+
185
+ expectTypeOf(authorization_signed).toExtend<
186
+ AuthorizationTempo.AuthorizationTempo<true>
187
+ >()
188
+ expect(authorization_signed.signature.type).toBe('webAuthn')
189
+ expect(authorization_signed.signature.metadata).toBeDefined()
190
+ expect(authorization_signed.signature.publicKey).toEqual(
191
+ signatureEnvelope.publicKey,
192
+ )
193
+ })
194
+
195
+ test('behavior: rpc', () => {
196
+ {
197
+ const authorization = AuthorizationTempo.from({
198
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
199
+ chainId: '0x1',
200
+ nonce: '0x1',
201
+ signature: {
202
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
203
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
204
+ yParity: '0x0',
205
+ type: 'secp256k1',
206
+ },
207
+ })
208
+ expectTypeOf(
209
+ authorization,
210
+ ).toExtend<AuthorizationTempo.AuthorizationTempo>()
211
+ expect(authorization).toMatchInlineSnapshot(
212
+ `
213
+ {
214
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
215
+ "chainId": 1,
216
+ "nonce": 1n,
217
+ "signature": {
218
+ "signature": {
219
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
220
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
221
+ "yParity": 0,
222
+ },
223
+ "type": "secp256k1",
224
+ },
225
+ }
226
+ `,
227
+ )
228
+ }
229
+ })
230
+ })
231
+
232
+ describe('fromRpc', () => {
233
+ test('secp256k1', () => {
234
+ expect(
235
+ AuthorizationTempo.fromRpc({
236
+ address: '0x0000000000000000000000000000000000000000',
237
+ chainId: '0x1',
238
+ nonce: '0x1',
239
+ signature: {
240
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
241
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
242
+ yParity: '0x0',
243
+ type: 'secp256k1',
244
+ },
245
+ }),
246
+ ).toMatchInlineSnapshot(`
247
+ {
248
+ "address": "0x0000000000000000000000000000000000000000",
249
+ "chainId": 1,
250
+ "nonce": 1n,
251
+ "signature": {
252
+ "signature": {
253
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
254
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
255
+ "yParity": 0,
256
+ },
257
+ "type": "secp256k1",
258
+ },
259
+ }
260
+ `)
261
+ })
262
+
263
+ test('p256', () => {
264
+ const result = AuthorizationTempo.fromRpc({
265
+ address: '0x0000000000000000000000000000000000000000',
266
+ chainId: '0x1',
267
+ nonce: '0x1',
268
+ signature: {
269
+ prehash: true,
270
+ pubKeyX:
271
+ '0x0000000000000000000000000000000000000000000000000000000000000001',
272
+ pubKeyY:
273
+ '0x0000000000000000000000000000000000000000000000000000000000000002',
274
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
275
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
276
+ type: 'p256',
277
+ },
278
+ })
279
+ expect(result.signature.type).toBe('p256')
280
+ expect(result.signature).toHaveProperty('prehash', true)
281
+ expect(result.signature).toHaveProperty('publicKey')
282
+ })
283
+
284
+ test('webAuthn', () => {
285
+ const result = AuthorizationTempo.fromRpc({
286
+ address: '0x0000000000000000000000000000000000000000',
287
+ chainId: '0x1',
288
+ nonce: '0x1',
289
+ signature: {
290
+ pubKeyX:
291
+ '0x0000000000000000000000000000000000000000000000000000000000000001',
292
+ pubKeyY:
293
+ '0x0000000000000000000000000000000000000000000000000000000000000002',
294
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
295
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
296
+ type: 'webAuthn',
297
+ webauthnData:
298
+ '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
299
+ },
300
+ })
301
+ expect(result.signature.type).toBe('webAuthn')
302
+ expect(result.signature).toHaveProperty('metadata')
303
+ expect(result.signature).toHaveProperty('publicKey')
304
+ })
305
+ })
306
+
307
+ describe('fromRpcList', () => {
308
+ test('secp256k1', () => {
309
+ expect(
310
+ AuthorizationTempo.fromRpcList([
311
+ {
312
+ address: '0x0000000000000000000000000000000000000000',
313
+ chainId: '0x1',
314
+ nonce: '0x1',
315
+ signature: {
316
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
317
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
318
+ yParity: '0x0',
319
+ type: 'secp256k1',
320
+ },
321
+ },
322
+ {
323
+ address: '0x0000000000000000000000000000000000000000',
324
+ chainId: '0x1',
325
+ nonce: '0x1',
326
+ signature: {
327
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
328
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
329
+ yParity: '0x0',
330
+ type: 'secp256k1',
331
+ },
332
+ },
333
+ ]),
334
+ ).toMatchInlineSnapshot(`
335
+ [
336
+ {
337
+ "address": "0x0000000000000000000000000000000000000000",
338
+ "chainId": 1,
339
+ "nonce": 1n,
340
+ "signature": {
341
+ "signature": {
342
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
343
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
344
+ "yParity": 0,
345
+ },
346
+ "type": "secp256k1",
347
+ },
348
+ },
349
+ {
350
+ "address": "0x0000000000000000000000000000000000000000",
351
+ "chainId": 1,
352
+ "nonce": 1n,
353
+ "signature": {
354
+ "signature": {
355
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
356
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
357
+ "yParity": 0,
358
+ },
359
+ "type": "secp256k1",
360
+ },
361
+ },
362
+ ]
363
+ `)
364
+ })
365
+
366
+ test('p256', () => {
367
+ expect(
368
+ AuthorizationTempo.fromRpcList([
369
+ {
370
+ address: '0x0000000000000000000000000000000000000000',
371
+ chainId: '0x1',
372
+ nonce: '0x1',
373
+ signature: {
374
+ prehash: true,
375
+ pubKeyX:
376
+ '0x0000000000000000000000000000000000000000000000000000000000000001',
377
+ pubKeyY:
378
+ '0x0000000000000000000000000000000000000000000000000000000000000002',
379
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
380
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
381
+ type: 'p256',
382
+ },
383
+ },
384
+ {
385
+ address: '0x0000000000000000000000000000000000000001',
386
+ chainId: '0x2',
387
+ nonce: '0x2',
388
+ signature: {
389
+ prehash: false,
390
+ pubKeyX:
391
+ '0x0000000000000000000000000000000000000000000000000000000000000003',
392
+ pubKeyY:
393
+ '0x0000000000000000000000000000000000000000000000000000000000000004',
394
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
395
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
396
+ type: 'p256',
397
+ },
398
+ },
399
+ ]),
400
+ ).toMatchInlineSnapshot(`
401
+ [
402
+ {
403
+ "address": "0x0000000000000000000000000000000000000000",
404
+ "chainId": 1,
405
+ "nonce": 1n,
406
+ "signature": {
407
+ "prehash": true,
408
+ "publicKey": {
409
+ "prefix": 4,
410
+ "x": 1n,
411
+ "y": 2n,
412
+ },
413
+ "signature": {
414
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
415
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
416
+ },
417
+ "type": "p256",
418
+ },
419
+ },
420
+ {
421
+ "address": "0x0000000000000000000000000000000000000001",
422
+ "chainId": 2,
423
+ "nonce": 2n,
424
+ "signature": {
425
+ "prehash": false,
426
+ "publicKey": {
427
+ "prefix": 4,
428
+ "x": 3n,
429
+ "y": 4n,
430
+ },
431
+ "signature": {
432
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
433
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
434
+ },
435
+ "type": "p256",
436
+ },
437
+ },
438
+ ]
439
+ `)
440
+ })
441
+
442
+ test('webAuthn', () => {
443
+ expect(
444
+ AuthorizationTempo.fromRpcList([
445
+ {
446
+ address: '0x0000000000000000000000000000000000000000',
447
+ chainId: '0x1',
448
+ nonce: '0x1',
449
+ signature: {
450
+ pubKeyX:
451
+ '0x0000000000000000000000000000000000000000000000000000000000000001',
452
+ pubKeyY:
453
+ '0x0000000000000000000000000000000000000000000000000000000000000002',
454
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
455
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
456
+ type: 'webAuthn',
457
+ webauthnData:
458
+ '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
459
+ },
460
+ },
461
+ {
462
+ address: '0x0000000000000000000000000000000000000001',
463
+ chainId: '0x2',
464
+ nonce: '0x2',
465
+ signature: {
466
+ pubKeyX:
467
+ '0x0000000000000000000000000000000000000000000000000000000000000003',
468
+ pubKeyY:
469
+ '0x0000000000000000000000000000000000000000000000000000000000000004',
470
+ r: '0x1',
471
+ s: '0x2',
472
+ type: 'webAuthn',
473
+ webauthnData:
474
+ '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
475
+ },
476
+ },
477
+ ]),
478
+ ).toMatchInlineSnapshot(`
479
+ [
480
+ {
481
+ "address": "0x0000000000000000000000000000000000000000",
482
+ "chainId": 1,
483
+ "nonce": 1n,
484
+ "signature": {
485
+ "metadata": {
486
+ "authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
487
+ "clientDataJSON": "{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}",
488
+ },
489
+ "publicKey": {
490
+ "prefix": 4,
491
+ "x": 1n,
492
+ "y": 2n,
493
+ },
494
+ "signature": {
495
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
496
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
497
+ },
498
+ "type": "webAuthn",
499
+ },
500
+ },
501
+ {
502
+ "address": "0x0000000000000000000000000000000000000001",
503
+ "chainId": 2,
504
+ "nonce": 2n,
505
+ "signature": {
506
+ "metadata": {
507
+ "authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
508
+ "clientDataJSON": "{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}",
509
+ },
510
+ "publicKey": {
511
+ "prefix": 4,
512
+ "x": 3n,
513
+ "y": 4n,
514
+ },
515
+ "signature": {
516
+ "r": 1n,
517
+ "s": 2n,
518
+ },
519
+ "type": "webAuthn",
520
+ },
521
+ },
522
+ ]
523
+ `)
524
+ })
525
+
526
+ test('mixed signature types', () => {
527
+ expect(
528
+ AuthorizationTempo.fromRpcList([
529
+ {
530
+ address: '0x0000000000000000000000000000000000000000',
531
+ chainId: '0x1',
532
+ nonce: '0x1',
533
+ signature: {
534
+ r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d',
535
+ s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540',
536
+ yParity: '0x0',
537
+ type: 'secp256k1',
538
+ },
539
+ },
540
+ {
541
+ address: '0x0000000000000000000000000000000000000001',
542
+ chainId: '0x2',
543
+ nonce: '0x2',
544
+ signature: {
545
+ prehash: true,
546
+ pubKeyX:
547
+ '0x0000000000000000000000000000000000000000000000000000000000000003',
548
+ pubKeyY:
549
+ '0x0000000000000000000000000000000000000000000000000000000000000004',
550
+ r: '0x1',
551
+ s: '0x2',
552
+ type: 'p256',
553
+ },
554
+ },
555
+ {
556
+ address: '0x0000000000000000000000000000000000000002',
557
+ chainId: '0x3',
558
+ nonce: '0x3',
559
+ signature: {
560
+ pubKeyX:
561
+ '0x0000000000000000000000000000000000000000000000000000000000000005',
562
+ pubKeyY:
563
+ '0x0000000000000000000000000000000000000000000000000000000000000006',
564
+ r: '0x3',
565
+ s: '0x4',
566
+ type: 'webAuthn',
567
+ webauthnData:
568
+ '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
569
+ },
570
+ },
571
+ ]),
572
+ ).toMatchInlineSnapshot(`
573
+ [
574
+ {
575
+ "address": "0x0000000000000000000000000000000000000000",
576
+ "chainId": 1,
577
+ "nonce": 1n,
578
+ "signature": {
579
+ "signature": {
580
+ "r": 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
581
+ "s": 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
582
+ "yParity": 0,
583
+ },
584
+ "type": "secp256k1",
585
+ },
586
+ },
587
+ {
588
+ "address": "0x0000000000000000000000000000000000000001",
589
+ "chainId": 2,
590
+ "nonce": 2n,
591
+ "signature": {
592
+ "prehash": true,
593
+ "publicKey": {
594
+ "prefix": 4,
595
+ "x": 3n,
596
+ "y": 4n,
597
+ },
598
+ "signature": {
599
+ "r": 1n,
600
+ "s": 2n,
601
+ },
602
+ "type": "p256",
603
+ },
604
+ },
605
+ {
606
+ "address": "0x0000000000000000000000000000000000000002",
607
+ "chainId": 3,
608
+ "nonce": 3n,
609
+ "signature": {
610
+ "metadata": {
611
+ "authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
612
+ "clientDataJSON": "{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}",
613
+ },
614
+ "publicKey": {
615
+ "prefix": 4,
616
+ "x": 5n,
617
+ "y": 6n,
618
+ },
619
+ "signature": {
620
+ "r": 3n,
621
+ "s": 4n,
622
+ },
623
+ "type": "webAuthn",
624
+ },
625
+ },
626
+ ]
627
+ `)
628
+ })
629
+ })
630
+
631
+ describe('fromTuple', () => {
632
+ test('default', () => {
633
+ const tuple = [
634
+ '0x1',
635
+ '0x0000000000000000000000000000000000000000',
636
+ '0x3',
637
+ ] as const satisfies AuthorizationTempo.Tuple
638
+ const authorization = AuthorizationTempo.fromTuple(tuple)
639
+ expect(authorization).toMatchInlineSnapshot(`
640
+ {
641
+ "address": "0x0000000000000000000000000000000000000000",
642
+ "chainId": 1,
643
+ "nonce": 3n,
644
+ }
645
+ `)
646
+ })
647
+
648
+ test('behavior: zeroish nonce + chainId', () => {
649
+ const tuple = [
650
+ '0x',
651
+ '0x0000000000000000000000000000000000000000',
652
+ '0x',
653
+ ] as const satisfies AuthorizationTempo.Tuple
654
+ const authorization = AuthorizationTempo.fromTuple(tuple)
655
+ expect(authorization).toMatchInlineSnapshot(`
656
+ {
657
+ "address": "0x0000000000000000000000000000000000000000",
658
+ "chainId": 0,
659
+ "nonce": 0n,
660
+ }
661
+ `)
662
+ })
663
+
664
+ test('behavior: signature (secp256k1)', () => {
665
+ const signatureEnvelope = SignatureEnvelope.from({
666
+ signature: { r: 1n, s: 2n, yParity: 0 },
667
+ type: 'secp256k1',
668
+ })
669
+ const serialized = SignatureEnvelope.serialize(signatureEnvelope)
670
+
671
+ const tuple = [
672
+ '0x1',
673
+ '0x0000000000000000000000000000000000000000',
674
+ '0x3',
675
+ serialized,
676
+ ] as const satisfies AuthorizationTempo.Tuple
677
+ const authorization = AuthorizationTempo.fromTuple(tuple)
678
+ expect(authorization).toMatchInlineSnapshot(`
679
+ {
680
+ "address": "0x0000000000000000000000000000000000000000",
681
+ "chainId": 1,
682
+ "nonce": 3n,
683
+ "signature": {
684
+ "signature": {
685
+ "r": 1n,
686
+ "s": 2n,
687
+ "yParity": 0,
688
+ },
689
+ "type": "secp256k1",
690
+ },
691
+ }
692
+ `)
693
+ })
694
+
695
+ test('behavior: signature (p256)', () => {
696
+ const signatureEnvelope = SignatureEnvelope.from({
697
+ prehash: true,
698
+ publicKey: { prefix: 4, x: 1n, y: 2n },
699
+ signature: { r: 3n, s: 4n },
700
+ type: 'p256',
701
+ })
702
+ const serialized = SignatureEnvelope.serialize(signatureEnvelope)
703
+
704
+ const tuple = [
705
+ '0x1',
706
+ '0x0000000000000000000000000000000000000000',
707
+ '0x3',
708
+ serialized,
709
+ ] as const satisfies AuthorizationTempo.Tuple
710
+ const authorization = AuthorizationTempo.fromTuple(tuple)
711
+ expect(authorization.signature?.type).toBe('p256')
712
+ })
713
+ })
714
+
715
+ describe('fromTupleList', () => {
716
+ test('default', () => {
717
+ const tupleList = [
718
+ ['0x01', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x28'],
719
+ ['0x03', '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c', '0x14'],
720
+ ] as const satisfies AuthorizationTempo.TupleList
721
+ const authorization = AuthorizationTempo.fromTupleList(tupleList)
722
+ expect(authorization).toMatchInlineSnapshot(`
723
+ [
724
+ {
725
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
726
+ "chainId": 1,
727
+ "nonce": 40n,
728
+ },
729
+ {
730
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
731
+ "chainId": 3,
732
+ "nonce": 20n,
733
+ },
734
+ ]
735
+ `)
736
+ })
737
+
738
+ test('behavior: signature', () => {
739
+ const signatureEnvelope1 = SignatureEnvelope.from({
740
+ signature: { r: 1n, s: 2n, yParity: 0 },
741
+ type: 'secp256k1',
742
+ })
743
+ const signatureEnvelope2 = SignatureEnvelope.from({
744
+ signature: { r: 4n, s: 5n, yParity: 0 },
745
+ type: 'secp256k1',
746
+ })
747
+
748
+ const authorization = AuthorizationTempo.fromTupleList([
749
+ [
750
+ '0x05',
751
+ '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
752
+ '0x2a',
753
+ SignatureEnvelope.serialize(signatureEnvelope1),
754
+ ],
755
+ [
756
+ '0x02',
757
+ '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
758
+ '0x2b',
759
+ SignatureEnvelope.serialize(signatureEnvelope2),
760
+ ],
761
+ ])
762
+ expect(authorization).toMatchInlineSnapshot(`
763
+ [
764
+ {
765
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
766
+ "chainId": 5,
767
+ "nonce": 42n,
768
+ "signature": {
769
+ "signature": {
770
+ "r": 1n,
771
+ "s": 2n,
772
+ "yParity": 0,
773
+ },
774
+ "type": "secp256k1",
775
+ },
776
+ },
777
+ {
778
+ "address": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
779
+ "chainId": 2,
780
+ "nonce": 43n,
781
+ "signature": {
782
+ "signature": {
783
+ "r": 4n,
784
+ "s": 5n,
785
+ "yParity": 0,
786
+ },
787
+ "type": "secp256k1",
788
+ },
789
+ },
790
+ ]
791
+ `)
792
+ })
793
+ })
794
+
795
+ describe('getSignPayload', () => {
796
+ test('default', () => {
797
+ expect(
798
+ AuthorizationTempo.getSignPayload({
799
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
800
+ chainId: 1,
801
+ nonce: 40n,
802
+ }),
803
+ ).toMatchInlineSnapshot(
804
+ `"0x5919da563810a99caf657d42bd10905adbd28b3b89b8a4577efa471e5e4b3914"`,
805
+ )
806
+
807
+ expect(
808
+ AuthorizationTempo.getSignPayload({
809
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
810
+ chainId: 69,
811
+ nonce: 420n,
812
+ }),
813
+ ).toMatchInlineSnapshot(
814
+ `"0x7bdd120f6437316be99b11232d472bb0209d20d7c564f4dfbad855189e830b15"`,
815
+ )
816
+ })
817
+ })
818
+
819
+ describe('hash', () => {
820
+ test('default', () => {
821
+ expect(
822
+ AuthorizationTempo.hash({
823
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
824
+ chainId: 1,
825
+ nonce: 40n,
826
+ }),
827
+ ).toMatchInlineSnapshot(
828
+ `"0x5919da563810a99caf657d42bd10905adbd28b3b89b8a4577efa471e5e4b3914"`,
829
+ )
830
+
831
+ expect(
832
+ AuthorizationTempo.hash({
833
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
834
+ chainId: 69,
835
+ nonce: 420n,
836
+ }),
837
+ ).toMatchInlineSnapshot(
838
+ `"0x7bdd120f6437316be99b11232d472bb0209d20d7c564f4dfbad855189e830b15"`,
839
+ )
840
+ })
841
+
842
+ test('options: presign equals getSignPayload', () => {
843
+ const authorization = {
844
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
845
+ chainId: 1,
846
+ nonce: 40n,
847
+ } as const
848
+ const payload = AuthorizationTempo.getSignPayload(authorization)
849
+ const hash_presign = AuthorizationTempo.hash(authorization, {
850
+ presign: true,
851
+ })
852
+ expect(hash_presign).toEqual(payload)
853
+ })
854
+ })
855
+
856
+ describe('toRpc', () => {
857
+ test('secp256k1', () => {
858
+ expect(
859
+ AuthorizationTempo.toRpc({
860
+ address: '0x0000000000000000000000000000000000000000',
861
+ chainId: 1,
862
+ nonce: 1n,
863
+ signature: {
864
+ signature: {
865
+ r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
866
+ s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
867
+ yParity: 0,
868
+ },
869
+ type: 'secp256k1',
870
+ },
871
+ }),
872
+ ).toMatchInlineSnapshot(`
873
+ {
874
+ "address": "0x0000000000000000000000000000000000000000",
875
+ "chainId": "0x1",
876
+ "nonce": "0x1",
877
+ "signature": {
878
+ "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d",
879
+ "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540",
880
+ "type": "secp256k1",
881
+ "yParity": "0x0",
882
+ },
883
+ }
884
+ `)
885
+ })
886
+
887
+ test('p256', () => {
888
+ const result = AuthorizationTempo.toRpc({
889
+ address: '0x0000000000000000000000000000000000000000',
890
+ chainId: 1,
891
+ nonce: 1n,
892
+ signature: {
893
+ prehash: true,
894
+ publicKey: { prefix: 4, x: 1n, y: 2n },
895
+ signature: {
896
+ r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
897
+ s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
898
+ },
899
+ type: 'p256',
900
+ },
901
+ })
902
+ expect(result.signature.type).toBe('p256')
903
+ })
904
+
905
+ test('webAuthn', () => {
906
+ const result = AuthorizationTempo.toRpc({
907
+ address: '0x0000000000000000000000000000000000000000',
908
+ chainId: 1,
909
+ nonce: 1n,
910
+ signature: {
911
+ metadata: {
912
+ authenticatorData: '0x1234',
913
+ clientDataJSON: '0x5678',
914
+ },
915
+ publicKey: { prefix: 4, x: 1n, y: 2n },
916
+ signature: {
917
+ r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
918
+ s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
919
+ },
920
+ type: 'webAuthn',
921
+ },
922
+ })
923
+ expect(result.signature.type).toBe('webAuthn')
924
+ })
925
+ })
926
+
927
+ describe('toRpcList', () => {
928
+ test('default', () => {
929
+ expect(
930
+ AuthorizationTempo.toRpcList([
931
+ {
932
+ address: '0x0000000000000000000000000000000000000000',
933
+ chainId: 1,
934
+ nonce: 1n,
935
+ signature: {
936
+ signature: {
937
+ r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
938
+ s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
939
+ yParity: 0,
940
+ },
941
+ type: 'secp256k1',
942
+ },
943
+ },
944
+ ]),
945
+ ).toMatchInlineSnapshot(`
946
+ [
947
+ {
948
+ "address": "0x0000000000000000000000000000000000000000",
949
+ "chainId": "0x1",
950
+ "nonce": "0x1",
951
+ "signature": {
952
+ "r": "0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d",
953
+ "s": "0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540",
954
+ "type": "secp256k1",
955
+ "yParity": "0x0",
956
+ },
957
+ },
958
+ ]
959
+ `)
960
+ })
961
+ })
962
+
963
+ describe('toTuple', () => {
964
+ test('default', () => {
965
+ {
966
+ const authorization = AuthorizationTempo.from({
967
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
968
+ chainId: 1,
969
+ nonce: 40n,
970
+ })
971
+ const tuple = AuthorizationTempo.toTuple(authorization)
972
+ expect(tuple).toMatchInlineSnapshot(`
973
+ [
974
+ "0x1",
975
+ "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
976
+ "0x28",
977
+ ]
978
+ `)
979
+ }
980
+
981
+ {
982
+ const signatureEnvelope: SignatureEnvelope.Secp256k1 = {
983
+ signature: { r: 1n, s: 2n, yParity: 0 },
984
+ type: 'secp256k1',
985
+ }
986
+ const authorization = AuthorizationTempo.from({
987
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
988
+ chainId: 1,
989
+ nonce: 40n,
990
+ signature: signatureEnvelope,
991
+ })
992
+ const tuple = AuthorizationTempo.toTuple(authorization)
993
+ expect(tuple).toMatchInlineSnapshot(`
994
+ [
995
+ "0x1",
996
+ "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
997
+ "0x28",
998
+ "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021b",
999
+ ]
1000
+ `)
1001
+ }
1002
+
1003
+ {
1004
+ const authorization = AuthorizationTempo.from({
1005
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1006
+ chainId: 0,
1007
+ nonce: 0n,
1008
+ })
1009
+ const tuple = AuthorizationTempo.toTuple(authorization)
1010
+ expect(tuple).toMatchInlineSnapshot(`
1011
+ [
1012
+ "0x",
1013
+ "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
1014
+ "0x",
1015
+ ]
1016
+ `)
1017
+ }
1018
+ })
1019
+ })
1020
+
1021
+ describe('toTupleList', () => {
1022
+ test('default', () => {
1023
+ {
1024
+ const tuple = AuthorizationTempo.toTupleList([])
1025
+ expect(tuple).toMatchInlineSnapshot('[]')
1026
+ }
1027
+
1028
+ {
1029
+ const authorization_1 = AuthorizationTempo.from({
1030
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1031
+ chainId: 1,
1032
+ nonce: 40n,
1033
+ })
1034
+ const authorization_2 = AuthorizationTempo.from({
1035
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1036
+ chainId: 3,
1037
+ nonce: 20n,
1038
+ })
1039
+ const tuple = AuthorizationTempo.toTupleList([
1040
+ authorization_1,
1041
+ authorization_2,
1042
+ ])
1043
+ expect(tuple).toMatchInlineSnapshot(`
1044
+ [
1045
+ [
1046
+ "0x1",
1047
+ "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
1048
+ "0x28",
1049
+ ],
1050
+ [
1051
+ "0x3",
1052
+ "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
1053
+ "0x14",
1054
+ ],
1055
+ ]
1056
+ `)
1057
+ }
1058
+
1059
+ {
1060
+ const signatureEnvelope1 = SignatureEnvelope.from({
1061
+ signature: { r: 1n, s: 2n, yParity: 0 },
1062
+ type: 'secp256k1',
1063
+ })
1064
+ const signatureEnvelope2 = SignatureEnvelope.from({
1065
+ signature: { r: 4n, s: 5n, yParity: 0 },
1066
+ type: 'secp256k1',
1067
+ })
1068
+ const authorization_3 = AuthorizationTempo.from({
1069
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1070
+ chainId: 5,
1071
+ nonce: 42n,
1072
+ signature: signatureEnvelope1,
1073
+ })
1074
+ const authorization_4 = AuthorizationTempo.from({
1075
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1076
+ chainId: 2,
1077
+ nonce: 43n,
1078
+ signature: signatureEnvelope2,
1079
+ })
1080
+ const tuple = AuthorizationTempo.toTupleList([
1081
+ authorization_3,
1082
+ authorization_4,
1083
+ ])
1084
+ expect(tuple).toMatchInlineSnapshot(`
1085
+ [
1086
+ [
1087
+ "0x5",
1088
+ "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
1089
+ "0x2a",
1090
+ "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021b",
1091
+ ],
1092
+ [
1093
+ "0x2",
1094
+ "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
1095
+ "0x2b",
1096
+ "0x000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000051b",
1097
+ ],
1098
+ ]
1099
+ `)
1100
+ }
1101
+ })
1102
+
1103
+ test('behavior: undefined input returns empty', () => {
1104
+ const tuple = AuthorizationTempo.toTupleList()
1105
+ expect(tuple).toMatchInlineSnapshot('[]')
1106
+ })
1107
+ })
1108
+
1109
+ describe('signature type interoperability', () => {
1110
+ test('secp256k1 signature round trip', () => {
1111
+ const authorization = AuthorizationTempo.from({
1112
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1113
+ chainId: 1,
1114
+ nonce: 40n,
1115
+ })
1116
+
1117
+ const signature = Secp256k1.sign({
1118
+ payload: AuthorizationTempo.getSignPayload(authorization),
1119
+ privateKey: testPrivateKey,
1120
+ })
1121
+ const signatureEnvelope = SignatureEnvelope.from({
1122
+ signature,
1123
+ type: 'secp256k1',
1124
+ })
1125
+
1126
+ const signed = AuthorizationTempo.from(authorization, {
1127
+ signature: signatureEnvelope,
1128
+ })
1129
+ const rpc = AuthorizationTempo.toRpc(signed)
1130
+ const restored = AuthorizationTempo.fromRpc(rpc)
1131
+
1132
+ expect(restored).toEqual(signed)
1133
+ })
1134
+
1135
+ test('p256 signature round trip', () => {
1136
+ const authorization = AuthorizationTempo.from({
1137
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1138
+ chainId: 1,
1139
+ nonce: 40n,
1140
+ })
1141
+
1142
+ const privateKey = P256.randomPrivateKey()
1143
+ const publicKey = P256.getPublicKey({ privateKey })
1144
+ const payload = AuthorizationTempo.getSignPayload(authorization)
1145
+ const signature = P256.sign({ payload, privateKey })
1146
+
1147
+ const signatureEnvelope = SignatureEnvelope.from({
1148
+ prehash: true,
1149
+ publicKey,
1150
+ signature,
1151
+ type: 'p256',
1152
+ })
1153
+
1154
+ const signed = AuthorizationTempo.from(authorization, {
1155
+ signature: signatureEnvelope,
1156
+ })
1157
+ const rpc = AuthorizationTempo.toRpc(signed)
1158
+ const restored = AuthorizationTempo.fromRpc(rpc)
1159
+
1160
+ expect(restored.signature.type).toBe('p256')
1161
+ expect(restored.address).toEqual(signed.address)
1162
+ expect(restored.chainId).toEqual(signed.chainId)
1163
+ expect(restored.nonce).toEqual(signed.nonce)
1164
+ expect(restored.signature.type).toEqual(signed.signature.type)
1165
+ expect(restored.signature.prehash).toEqual(signed.signature.prehash)
1166
+ expect(restored.signature.publicKey).toEqual(signed.signature.publicKey)
1167
+ expect(restored.signature.signature?.r).toEqual(
1168
+ signed.signature.signature?.r,
1169
+ )
1170
+ expect(restored.signature.signature?.s).toEqual(
1171
+ signed.signature.signature?.s,
1172
+ )
1173
+ })
1174
+
1175
+ test('webAuthn signature round trip', () => {
1176
+ const authorization = AuthorizationTempo.from({
1177
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1178
+ chainId: 1,
1179
+ nonce: 40n,
1180
+ })
1181
+
1182
+ const signatureEnvelope = SignatureEnvelope.from({
1183
+ metadata: {
1184
+ authenticatorData:
1185
+ '0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000',
1186
+ clientDataJSON:
1187
+ '{"type":"webauthn.get","challenge":"","origin":"https://example.com","crossOrigin":false}',
1188
+ },
1189
+ publicKey: { prefix: 4, x: 1n, y: 2n },
1190
+ signature: {
1191
+ r: 44944627813007772897391531230081695102703289123332187696115181104739239197517n,
1192
+ s: 36528503505192438307355164441104001310566505351980369085208178712678799181120n,
1193
+ },
1194
+ type: 'webAuthn',
1195
+ })
1196
+
1197
+ const signed = AuthorizationTempo.from(authorization, {
1198
+ signature: signatureEnvelope,
1199
+ })
1200
+ const rpc = AuthorizationTempo.toRpc(signed)
1201
+ const restored = AuthorizationTempo.fromRpc(rpc)
1202
+
1203
+ expect(restored.signature.type).toBe('webAuthn')
1204
+ expect(restored.address).toEqual(signed.address)
1205
+ expect(restored.chainId).toEqual(signed.chainId)
1206
+ expect(restored.nonce).toEqual(signed.nonce)
1207
+ expect(restored.signature.type).toEqual(signed.signature.type)
1208
+ expect(restored.signature.metadata).toEqual(signed.signature.metadata)
1209
+ expect(restored.signature.publicKey).toEqual(signed.signature.publicKey)
1210
+ expect(restored.signature.signature?.r).toEqual(
1211
+ signed.signature.signature?.r,
1212
+ )
1213
+ expect(restored.signature.signature?.s).toEqual(
1214
+ signed.signature.signature?.s,
1215
+ )
1216
+ })
1217
+
1218
+ test('tuple serialization preserves signature type', () => {
1219
+ const signatureEnvelope = SignatureEnvelope.from({
1220
+ prehash: true,
1221
+ publicKey: { prefix: 4, x: 1n, y: 2n },
1222
+ signature: { r: 3n, s: 4n },
1223
+ type: 'p256',
1224
+ })
1225
+
1226
+ const authorization = AuthorizationTempo.from({
1227
+ address: '0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c',
1228
+ chainId: 1,
1229
+ nonce: 40n,
1230
+ signature: signatureEnvelope,
1231
+ })
1232
+
1233
+ const tuple = AuthorizationTempo.toTuple(authorization)
1234
+ const restored = AuthorizationTempo.fromTuple(tuple)
1235
+
1236
+ expect(restored.signature?.type).toBe('p256')
1237
+ })
1238
+ })
1239
+
1240
+ test('exports', () => {
1241
+ expect(Object.keys(AuthorizationTempo)).toMatchInlineSnapshot(`
1242
+ [
1243
+ "from",
1244
+ "fromRpc",
1245
+ "fromRpcList",
1246
+ "fromTuple",
1247
+ "fromTupleList",
1248
+ "getSignPayload",
1249
+ "hash",
1250
+ "toRpc",
1251
+ "toRpcList",
1252
+ "toTuple",
1253
+ "toTupleList",
1254
+ ]
1255
+ `)
1256
+ })