ox 1.8.10 → 1.8.12

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 (37) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/core/Authorization.d.ts.map +1 -1
  3. package/dist/core/Authorization.js +44 -6
  4. package/dist/core/Authorization.js.map +1 -1
  5. package/dist/core/Siwe.d.ts.map +1 -1
  6. package/dist/core/Siwe.js +1 -1
  7. package/dist/core/Siwe.js.map +1 -1
  8. package/dist/tempo/AccountConfig.d.ts +7 -17
  9. package/dist/tempo/AccountConfig.d.ts.map +1 -1
  10. package/dist/tempo/AccountConfig.js +8 -26
  11. package/dist/tempo/AccountConfig.js.map +1 -1
  12. package/dist/tempo/AccountOperation.d.ts +1 -1
  13. package/dist/tempo/AccountOperation.js +1 -1
  14. package/dist/tempo/index.d.ts +1 -3
  15. package/dist/tempo/index.d.ts.map +1 -1
  16. package/dist/tempo/index.js +1 -3
  17. package/dist/tempo/index.js.map +1 -1
  18. package/dist/zod/Authorization.d.ts.map +1 -1
  19. package/dist/zod/Authorization.js +6 -9
  20. package/dist/zod/Authorization.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/core/Authorization.ts +43 -6
  23. package/src/core/Siwe.ts +1 -1
  24. package/src/core/_test/Authorization.test.ts +166 -0
  25. package/src/core/_test/Siwe.test.ts +53 -0
  26. package/src/core/_test/TransactionEnvelopeEip7702.test.ts +66 -0
  27. package/src/tempo/AccountConfig.test.ts +34 -47
  28. package/src/tempo/AccountConfig.ts +9 -37
  29. package/src/tempo/AccountOperation.test.ts +36 -37
  30. package/src/tempo/AccountOperation.ts +1 -1
  31. package/src/tempo/SignatureEnvelope.test.ts +1 -3
  32. package/src/tempo/configurableAccounts.e2e.test.ts +1 -2
  33. package/src/tempo/index.ts +1 -3
  34. package/src/version.ts +1 -1
  35. package/src/zod/Authorization.ts +6 -24
  36. package/src/zod/_test/Authorization.test.ts +35 -2
  37. package/src/zod/_test/TransactionRequest.test.ts +1 -1
@@ -179,7 +179,11 @@ export declare namespace from {
179
179
  */
180
180
  export function fromRpc(authorization: Rpc): Signed {
181
181
  const { address, chainId, nonce } = authorization
182
- const signature = Signature.extract(authorization)!
182
+ // EIP-7702 permits any `y_parity` below 2**8 in an authorization tuple, so
183
+ // check `yParity` against one byte rather than against 0 or 1.
184
+ const signature = Signature.fromRpc(authorization)
185
+ Signature.assert({ r: signature.r, s: signature.s })
186
+ assertYParity(signature.yParity)
183
187
 
184
188
  return {
185
189
  address,
@@ -278,8 +282,18 @@ export function fromTuple<const tuple extends Tuple>(
278
282
  chainId: chainId === '0x' ? 0 : Number(chainId),
279
283
  nonce: nonce === '0x' ? 0n : BigInt(nonce),
280
284
  }
281
- if (yParity && r && s)
282
- args = { ...args, ...Signature.fromTuple([yParity, r, s]) }
285
+ if (yParity && r && s) {
286
+ // EIP-7702 permits any `y_parity` below 2**8 in an authorization tuple, so
287
+ // check `yParity` against one byte rather than against 0 or 1.
288
+ const signature = {
289
+ r: Hex.padLeft(r, 32),
290
+ s: Hex.padLeft(s, 32),
291
+ yParity: yParity === '0x' ? 0 : Number(yParity),
292
+ }
293
+ Signature.assert({ r: signature.r, s: signature.s })
294
+ assertYParity(signature.yParity)
295
+ args = { ...args, ...signature }
296
+ }
283
297
  return from(args) as never
284
298
  }
285
299
 
@@ -500,6 +514,7 @@ export declare namespace hash {
500
514
  */
501
515
  export function toRpc(authorization: toRpc.Input): Rpc {
502
516
  const { address, chainId, nonce, ...signature } = authorization
517
+ assertYParity(Number(signature.yParity))
503
518
 
504
519
  return {
505
520
  address,
@@ -576,13 +591,23 @@ export declare namespace toRpcList {
576
591
  export function toTuple<const authorization extends Authorization>(
577
592
  authorization: authorization,
578
593
  ): toTuple.ReturnType<authorization> {
579
- const { address, chainId, nonce } = authorization
580
- const signature = Signature.extract(authorization)
594
+ const { address, chainId, nonce, r, s, yParity } = authorization
595
+ const signature = Signature.extract({ r, s })
596
+ if (signature && typeof yParity !== 'undefined') assertYParity(yParity)
581
597
  return [
582
598
  chainId ? Hex.fromNumber(chainId) : '0x',
583
599
  address,
584
600
  nonce ? Hex.fromNumber(nonce) : '0x',
585
- ...(signature ? Signature.toTuple(signature) : []),
601
+ // EIP-7702 permits any `y_parity` below 2**8 in an authorization tuple, and a
602
+ // tuple that fails recovery does not invalidate the transaction. Encode
603
+ // `yParity` as is, so that serialization preserves the transaction hash.
604
+ ...(signature
605
+ ? [
606
+ yParity ? Hex.fromNumber(yParity, { size: 1 }) : '0x',
607
+ Hex.trimLeft(signature.r),
608
+ Hex.trimLeft(signature.s),
609
+ ]
610
+ : []),
586
611
  ] as never
587
612
  }
588
613
 
@@ -656,3 +681,15 @@ export declare namespace toTupleList {
656
681
 
657
682
  type ErrorType = Errors.GlobalErrorType
658
683
  }
684
+
685
+ // Asserts that an EIP-7702 authorization `yParity` fits in one byte.
686
+ function assertYParity(yParity: number) {
687
+ if (Number.isInteger(yParity) && yParity >= 0 && yParity < 256) return
688
+ throw new Hex.IntegerOutOfRangeError({
689
+ max: '255',
690
+ min: '0',
691
+ signed: false,
692
+ size: 1,
693
+ value: `${yParity}`,
694
+ })
695
+ }
package/src/core/Siwe.ts CHANGED
@@ -4,7 +4,7 @@ import * as Hex from './Hex.js'
4
4
  import type { ExactPartial } from './internal/types.js'
5
5
 
6
6
  export const domainRegex =
7
- /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(:[0-9]{1,5})?$/
7
+ /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+(?:[a-zA-Z]{2,63}|[xX][nN]--[a-zA-Z0-9-]{0,58}[a-zA-Z0-9])(:[0-9]{1,5})?$/
8
8
 
9
9
  export const ipRegex =
10
10
  /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(:[0-9]{1,5})?$/
@@ -151,6 +151,43 @@ describe('fromRpc', () => {
151
151
  }
152
152
  `)
153
153
  })
154
+
155
+ test('behavior: yParity above 1', () => {
156
+ expect(
157
+ Authorization.fromRpc({
158
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
159
+ chainId: '0x0',
160
+ nonce: '0x6',
161
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
162
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
163
+ yParity: '0x1c',
164
+ }),
165
+ ).toMatchInlineSnapshot(`
166
+ {
167
+ "address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
168
+ "chainId": 0,
169
+ "nonce": 6n,
170
+ "r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
171
+ "s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
172
+ "yParity": 28,
173
+ }
174
+ `)
175
+ })
176
+
177
+ test('error: yParity above 2**8 - 1', () => {
178
+ expect(() =>
179
+ Authorization.fromRpc({
180
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
181
+ chainId: '0x0',
182
+ nonce: '0x6',
183
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
184
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
185
+ yParity: '0x100',
186
+ }),
187
+ ).toThrowErrorMatchingInlineSnapshot(
188
+ `[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
189
+ )
190
+ })
154
191
  })
155
192
 
156
193
  describe('fromRpcList', () => {
@@ -251,6 +288,44 @@ describe('fromTuple', () => {
251
288
  }
252
289
  `)
253
290
  })
291
+
292
+ test('behavior: yParity above 1', () => {
293
+ const tuple = [
294
+ '0x',
295
+ '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
296
+ '0x06',
297
+ '0x1c',
298
+ '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
299
+ '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
300
+ ] as const satisfies Authorization.Tuple
301
+ const authorization = Authorization.fromTuple(tuple)
302
+ expect(authorization).toMatchInlineSnapshot(`
303
+ {
304
+ "address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
305
+ "chainId": 0,
306
+ "nonce": 6n,
307
+ "r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
308
+ "s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
309
+ "yParity": 28,
310
+ }
311
+ `)
312
+ })
313
+
314
+ test('error: yParity above 2**8 - 1', () => {
315
+ const tuple = [
316
+ '0x',
317
+ '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
318
+ '0x06',
319
+ '0x0100',
320
+ '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
321
+ '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
322
+ ] as const satisfies Authorization.Tuple
323
+ expect(() =>
324
+ Authorization.fromTuple(tuple),
325
+ ).toThrowErrorMatchingInlineSnapshot(
326
+ `[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
327
+ )
328
+ })
254
329
  })
255
330
 
256
331
  describe('fromTupleList', () => {
@@ -454,6 +529,43 @@ describe('toRpc', () => {
454
529
  expect(fromBigint).toEqual(fromNumber)
455
530
  expect(fromBigint).toEqual(fromHex)
456
531
  })
532
+
533
+ test('behavior: yParity above 1', () => {
534
+ expect(
535
+ Authorization.toRpc({
536
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
537
+ chainId: 0,
538
+ nonce: 6n,
539
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
540
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
541
+ yParity: 28,
542
+ }),
543
+ ).toMatchInlineSnapshot(`
544
+ {
545
+ "address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
546
+ "chainId": "0x0",
547
+ "nonce": "0x6",
548
+ "r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
549
+ "s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
550
+ "yParity": "0x1c",
551
+ }
552
+ `)
553
+ })
554
+
555
+ test('error: yParity above 2**8 - 1', () => {
556
+ expect(() =>
557
+ Authorization.toRpc({
558
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
559
+ chainId: 0,
560
+ nonce: 6n,
561
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
562
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
563
+ yParity: 256,
564
+ }),
565
+ ).toThrowErrorMatchingInlineSnapshot(
566
+ `[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
567
+ )
568
+ })
457
569
  })
458
570
 
459
571
  describe('toRpcList', () => {
@@ -540,6 +652,60 @@ describe('toTuple', () => {
540
652
  `)
541
653
  }
542
654
  })
655
+
656
+ test('behavior: yParity above 1', () => {
657
+ const authorization = Authorization.from({
658
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
659
+ chainId: 0,
660
+ nonce: 6n,
661
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
662
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
663
+ yParity: 28,
664
+ })
665
+ const tuple = Authorization.toTuple(authorization)
666
+ expect(tuple).toMatchInlineSnapshot(`
667
+ [
668
+ "0x",
669
+ "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
670
+ "0x6",
671
+ "0x1c",
672
+ "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
673
+ "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
674
+ ]
675
+ `)
676
+ })
677
+
678
+ test('error: yParity above 2**8 - 1', () => {
679
+ const authorization = Authorization.from({
680
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
681
+ chainId: 0,
682
+ nonce: 6n,
683
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
684
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
685
+ yParity: 256,
686
+ })
687
+ expect(() =>
688
+ Authorization.toTuple(authorization),
689
+ ).toThrowErrorMatchingInlineSnapshot(
690
+ `[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
691
+ )
692
+ })
693
+
694
+ test('error: yParity not an integer', () => {
695
+ const authorization = Authorization.from({
696
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
697
+ chainId: 0,
698
+ nonce: 6n,
699
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
700
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
701
+ yParity: Number.NaN,
702
+ })
703
+ expect(() =>
704
+ Authorization.toTuple(authorization),
705
+ ).toThrowErrorMatchingInlineSnapshot(
706
+ `[Hex.IntegerOutOfRangeError: Number \`NaN\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
707
+ )
708
+ })
543
709
  })
544
710
 
545
711
  describe('toTupleList', () => {
@@ -61,6 +61,40 @@ describe('createMessage', () => {
61
61
  0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
62
62
 
63
63
 
64
+ URI: https://example.com/path
65
+ Version: 1
66
+ Chain ID: 1
67
+ Nonce: foobarbaz
68
+ Issued At: 2023-02-01T00:00:00.000Z"
69
+ `)
70
+
71
+ expect(
72
+ Siwe.createMessage({
73
+ ...message,
74
+ domain: 'example.xn--p1ai',
75
+ }),
76
+ ).toMatchInlineSnapshot(`
77
+ "example.xn--p1ai wants you to sign in with your Ethereum account:
78
+ 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
79
+
80
+
81
+ URI: https://example.com/path
82
+ Version: 1
83
+ Chain ID: 1
84
+ Nonce: foobarbaz
85
+ Issued At: 2023-02-01T00:00:00.000Z"
86
+ `)
87
+
88
+ expect(
89
+ Siwe.createMessage({
90
+ ...message,
91
+ domain: 'example.XN--P1AI',
92
+ }),
93
+ ).toMatchInlineSnapshot(`
94
+ "example.XN--P1AI wants you to sign in with your Ethereum account:
95
+ 0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
96
+
97
+
64
98
  URI: https://example.com/path
65
99
  Version: 1
66
100
  Chain ID: 1
@@ -431,6 +465,12 @@ describe('createMessage', () => {
431
465
  'example.com:3000',
432
466
  'localhost:3000',
433
467
  '127.0.0.1:3000',
468
+ 'example.xN--p1ai',
469
+ 'example.xn--p1ai:443',
470
+ 'example.xn--vermgensberater-ctb',
471
+ // 63 octets: "xn--" plus 59 LDH characters.
472
+ `example.xn--${'a'.repeat(59)}`,
473
+ `example.${'a'.repeat(63)}`,
434
474
  ])('valid domain `%s`', (domain) => {
435
475
  expect(
436
476
  Siwe.createMessage({
@@ -449,6 +489,13 @@ describe('createMessage', () => {
449
489
  'http://127.0.0.1:3000',
450
490
  'foobarbaz',
451
491
  '-example.com',
492
+ 'example.xn--',
493
+ 'example.xn--p1ai-',
494
+ 'example.xx--p1ai',
495
+ 'xn--p1ai',
496
+ // 64 octets: one past the maximum label length.
497
+ `example.xn--${'a'.repeat(60)}`,
498
+ `example.${'a'.repeat(64)}`,
452
499
  ])('invalid domain `%s`', (domain) => {
453
500
  expect(() =>
454
501
  Siwe.createMessage({
@@ -459,6 +506,12 @@ describe('createMessage', () => {
459
506
  })
460
507
  })
461
508
 
509
+ describe('domainRegex', () => {
510
+ test('behavior: captures the port in group 3', () => {
511
+ expect(Siwe.domainRegex.exec('example.xn--p1ai:443')?.[3]).toBe(':443')
512
+ })
513
+ })
514
+
462
515
  describe('generateNonce', () => {
463
516
  test('default', () => {
464
517
  const nonce = Siwe.generateNonce()
@@ -181,6 +181,40 @@ describe('deserialize', () => {
181
181
  })
182
182
  })
183
183
 
184
+ test('behavior: authorization yParity above 1', () => {
185
+ // Mainnet transaction 0xaec8420968abd74e70ef5b3099d6ba7baa3f069c4f718d7c4d729d591cffcb09,
186
+ // whose authorization holds a `y_parity` of 28.
187
+ const serialized =
188
+ '0x04f8c90102843b9aca0084408206be830186a094db35624115a810cf541988294a57766cd02acc828080c0f85cf85a8094c498cea4bfedbb8de856491bdd9967e677775f4f061ca044754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512a027a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b19180a0287d894b2ebb8a178a55810b242af186c73de663382358363d58b42628bbded3a0678f589cd41571248f24df7e60912d05f14c76471b859f4abd956c612bf175ee'
189
+
190
+ const envelope = TxEnvelopeEip7702.deserialize(serialized)
191
+ expect(envelope).toMatchInlineSnapshot(`
192
+ {
193
+ "authorizationList": [
194
+ {
195
+ "address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
196
+ "chainId": 0,
197
+ "nonce": 6n,
198
+ "r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
199
+ "s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
200
+ "yParity": 28,
201
+ },
202
+ ],
203
+ "chainId": 1,
204
+ "gas": 100000n,
205
+ "maxFeePerGas": 1082263230n,
206
+ "maxPriorityFeePerGas": 1000000000n,
207
+ "nonce": 2n,
208
+ "r": "0x287d894b2ebb8a178a55810b242af186c73de663382358363d58b42628bbded3",
209
+ "s": "0x678f589cd41571248f24df7e60912d05f14c76471b859f4abd956c612bf175ee",
210
+ "to": "0xdb35624115a810cf541988294a57766cd02acc82",
211
+ "type": "eip7702",
212
+ "yParity": 0,
213
+ }
214
+ `)
215
+ expect(TxEnvelopeEip7702.serialize(envelope)).toBe(serialized)
216
+ })
217
+
184
218
  describe('raw', () => {
185
219
  test('default', () => {
186
220
  const serialized = `0x04${Rlp.fromHex([
@@ -529,6 +563,38 @@ describe('hash', () => {
529
563
  `"0xa5ccd813e459b9154917af19270091cf3312bd759af08e0e18cd2560ef586cf4"`,
530
564
  )
531
565
  })
566
+
567
+ test('behavior: authorization yParity above 1', () => {
568
+ // Mainnet transaction 0xaec8420968abd74e70ef5b3099d6ba7baa3f069c4f718d7c4d729d591cffcb09,
569
+ // whose authorization holds a `y_parity` of 28.
570
+ const envelope = TxEnvelopeEip7702.from({
571
+ authorizationList: [
572
+ {
573
+ address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
574
+ chainId: 0,
575
+ nonce: 6n,
576
+ r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
577
+ s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
578
+ yParity: 28,
579
+ },
580
+ ],
581
+ chainId: 1,
582
+ gas: 100000n,
583
+ maxFeePerGas: 1082263230n,
584
+ maxPriorityFeePerGas: 1000000000n,
585
+ nonce: 2n,
586
+ r: '0x287d894b2ebb8a178a55810b242af186c73de663382358363d58b42628bbded3',
587
+ s: '0x678f589cd41571248f24df7e60912d05f14c76471b859f4abd956c612bf175ee',
588
+ to: '0xdb35624115a810cf541988294a57766cd02acc82',
589
+ value: 0n,
590
+ yParity: 0,
591
+ })
592
+
593
+ const hash = TxEnvelopeEip7702.hash(envelope)
594
+ expect(hash).toMatchInlineSnapshot(
595
+ `"0xaec8420968abd74e70ef5b3099d6ba7baa3f069c4f718d7c4d729d591cffcb09"`,
596
+ )
597
+ })
532
598
  })
533
599
 
534
600
  describe('serialize', () => {
@@ -1,4 +1,3 @@
1
- import { factory } from '../../test/tempo/configurableAccounts.js'
2
1
  import { Hash, Hex, Rlp } from 'ox'
3
2
  import { AccountConfig } from 'ox/tempo'
4
3
  import { describe, expect, test } from 'vp/test'
@@ -10,13 +9,12 @@ const config = AccountConfig.from({
10
9
  owners: [{ owner: owner_1, weight: 1 }],
11
10
  threshold: 1,
12
11
  })
13
- const account = AccountConfig.getAddress(config, { factory })
12
+ const account = AccountConfig.getAddress(config)
14
13
 
15
14
  // Vectors from Tempo `crates/primitives/tests/configurable_account.rs`
16
15
  // (`configurable_account_hashes_follow_vectors_and_documented_layout`).
17
16
  const tempo = {
18
17
  account: '0x91847576f406d0842ad7c1a0c97c22a122e64278',
19
- factory: '0x9999999999999999999999999999999999999999',
20
18
  } as const
21
19
 
22
20
  describe('from', () => {
@@ -180,78 +178,67 @@ describe('fromUpgrade', () => {
180
178
  describe('getAddress', () => {
181
179
  test('example: matches the Tempo vectors', () => {
182
180
  expect({
183
- maxOwners: AccountConfig.getAddress(
184
- {
185
- owners: Array.from({ length: AccountConfig.maxOwners }, (_, i) => ({
186
- owner: Hex.padLeft(Hex.fromNumber(i + 1), 20),
187
- weight: 1,
188
- })),
189
- threshold: 8,
190
- },
191
- { factory: tempo.factory },
192
- ),
193
- single: AccountConfig.getAddress(config, { factory: tempo.factory }),
181
+ maxOwners: AccountConfig.getAddress({
182
+ owners: Array.from({ length: AccountConfig.maxOwners }, (_, i) => ({
183
+ owner: Hex.padLeft(Hex.fromNumber(i + 1), 20),
184
+ weight: 1,
185
+ })),
186
+ threshold: 8,
187
+ }),
188
+ single: AccountConfig.getAddress(config),
194
189
  }).toMatchInlineSnapshot(`
195
190
  {
196
- "maxOwners": "0x7a4279bb3f1b8b54d703484317f64eae6814e827",
197
- "single": "0x87c346a9029d675f296db533b12e146439cf20d5",
191
+ "maxOwners": "0x9859f0316567499ebcd81d3417c0622999d7179f",
192
+ "single": "0xcbb727e2489c904a905420e794e8275b6150bfe1",
198
193
  }
199
194
  `)
200
195
  })
201
196
 
202
- test('example: matches the frozen CREATE2 vector', () => {
197
+ test('example: matches the frozen keccak vector', () => {
203
198
  expect(account).toMatchInlineSnapshot(
204
- `"0x2318ebe50d1d476ec10854bfd949f96ea7737b68"`,
199
+ `"0xcbb727e2489c904a905420e794e8275b6150bfe1"`,
205
200
  )
206
201
  expect(account).not.toBe('0x8820d1497eeaf4f68e00b2cfc00a2f3b1dbb00da')
207
202
  })
208
203
 
209
204
  test('behavior: includes salt, threshold, and owners', () => {
210
205
  expect(
211
- AccountConfig.getAddress(
212
- {
213
- owners: [
214
- { owner: owner_1, weight: 1 },
215
- { owner: owner_2, weight: 2 },
216
- ],
217
- salt: `0x${'42'.repeat(32)}`,
218
- threshold: 2,
219
- },
220
- { factory },
221
- ),
222
- ).toMatchInlineSnapshot(`"0x1baa996a4f142d99999aa22f1cb1eb97eed2a24a"`)
206
+ AccountConfig.getAddress({
207
+ owners: [
208
+ { owner: owner_1, weight: 1 },
209
+ { owner: owner_2, weight: 2 },
210
+ ],
211
+ salt: `0x${'42'.repeat(32)}`,
212
+ threshold: 2,
213
+ }),
214
+ ).toMatchInlineSnapshot(`"0x870b14ffcb3d1bd52be7cc6e8358a35712fec535"`)
223
215
  })
224
216
 
225
217
  test('behavior: is stable and binds the salt', () => {
226
218
  expect({
227
- repeated: AccountConfig.getAddress(config, { factory }),
228
- salted: AccountConfig.getAddress(
229
- {
230
- ...config,
231
- salt: `0x${'42'.repeat(32)}`,
232
- },
233
- { factory },
234
- ),
219
+ repeated: AccountConfig.getAddress(config),
220
+ salted: AccountConfig.getAddress({
221
+ ...config,
222
+ salt: `0x${'42'.repeat(32)}`,
223
+ }),
235
224
  }).toMatchInlineSnapshot(`
236
225
  {
237
- "repeated": "0x2318ebe50d1d476ec10854bfd949f96ea7737b68",
238
- "salted": "0x70d2e44032514493b68641ce5182cc878baa51f0",
226
+ "repeated": "0xcbb727e2489c904a905420e794e8275b6150bfe1",
227
+ "salted": "0xfc6a724c4715d331ec47dc8c1636798956fd3e4d",
239
228
  }
240
229
  `)
241
230
  })
242
231
 
243
232
  test('error: rejects a current configuration', () => {
244
233
  expect(() =>
245
- AccountConfig.getAddress({ ...config, version: 1n }, { factory }),
234
+ AccountConfig.getAddress({ ...config, version: 1n }),
246
235
  ).toThrowErrorMatchingInlineSnapshot(
247
236
  `[AccountConfig.InvalidConfigError: Invalid account config: account address requires version zero.]`,
248
237
  )
249
238
  })
250
239
 
251
240
  test('behavior: accepts numeric zero for an initial configuration', () => {
252
- expect(
253
- AccountConfig.getAddress({ ...config, version: 0 }, { factory }),
254
- ).toBe(account)
241
+ expect(AccountConfig.getAddress({ ...config, version: 0 })).toBe(account)
255
242
  })
256
243
  })
257
244
 
@@ -308,7 +295,7 @@ describe('getSignPayload', () => {
308
295
  expect(
309
296
  AccountConfig.getSignPayload({ account, config, payload }),
310
297
  ).toMatchInlineSnapshot(
311
- `"0x32144254ec42f7a37b97e3a843667b527479f933320be553265e6594dc44ea87"`,
298
+ `"0x53a60618dd8fd4d01c2c94a4d9dc482dbb7b97115eb448a4590d153b933e549a"`,
312
299
  )
313
300
  })
314
301
 
@@ -449,14 +436,14 @@ describe('assert/validate', () => {
449
436
  })
450
437
  const rlp = Rlp.fromHex(AccountConfig.toTuple(boundary))
451
438
  expect({
452
- account: AccountConfig.getAddress(boundary, { factory }),
439
+ account: AccountConfig.getAddress(boundary),
453
440
  commitment: AccountConfig.getCommitment(boundary),
454
441
  rlpHash: Hash.keccak256(rlp),
455
442
  rlpLength: Hex.size(rlp),
456
443
  valid: AccountConfig.validate(boundary),
457
444
  }).toMatchInlineSnapshot(`
458
445
  {
459
- "account": "0x8400988285be93cba9391d445e473601633e5d62",
446
+ "account": "0x9859f0316567499ebcd81d3417c0622999d7179f",
460
447
  "commitment": "0xa9282ca5b73ac63b7e27f49cafa6ab13bd2aa79fc45267cf27342db73150cd46",
461
448
  "rlpHash": "0xbaf0d030add91caaa10815d2e99c942f1e39b0d199216973781adb4fc1af6955",
462
449
  "rlpLength": 1145,