ox 1.7.2 → 1.7.4

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 (103) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/tempo/KeyAuthorization.d.ts +1 -1
  3. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  4. package/dist/tempo/MultisigOperation.d.ts +42 -26
  5. package/dist/tempo/MultisigOperation.d.ts.map +1 -1
  6. package/dist/tempo/MultisigOperation.js +78 -48
  7. package/dist/tempo/MultisigOperation.js.map +1 -1
  8. package/dist/tempo/MultisigSimulation.d.ts +132 -0
  9. package/dist/tempo/MultisigSimulation.d.ts.map +1 -0
  10. package/dist/tempo/MultisigSimulation.js +140 -0
  11. package/dist/tempo/MultisigSimulation.js.map +1 -0
  12. package/dist/tempo/RpcSchemaTempo.d.ts +20 -10
  13. package/dist/tempo/RpcSchemaTempo.d.ts.map +1 -1
  14. package/dist/tempo/SignatureEnvelope.d.ts +9 -20
  15. package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
  16. package/dist/tempo/SignatureEnvelope.js +12 -18
  17. package/dist/tempo/SignatureEnvelope.js.map +1 -1
  18. package/dist/tempo/TransactionRequest.d.ts +6 -6
  19. package/dist/tempo/TransactionRequest.d.ts.map +1 -1
  20. package/dist/tempo/TransactionRequest.js +7 -7
  21. package/dist/tempo/TransactionRequest.js.map +1 -1
  22. package/dist/tempo/index.d.ts +4 -4
  23. package/dist/tempo/index.d.ts.map +1 -1
  24. package/dist/tempo/index.js +4 -4
  25. package/dist/tempo/index.js.map +1 -1
  26. package/dist/zod/tempo/AuthorizationTempo.d.ts +10 -130
  27. package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
  28. package/dist/zod/tempo/KeyAuthorization.d.ts +5 -65
  29. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  30. package/dist/zod/tempo/MultisigOperation.d.ts +0 -10
  31. package/dist/zod/tempo/MultisigOperation.d.ts.map +1 -1
  32. package/dist/zod/tempo/MultisigOperation.js +0 -3
  33. package/dist/zod/tempo/MultisigOperation.js.map +1 -1
  34. package/dist/zod/tempo/{MultisigWitness.d.ts → MultisigSimulation.d.ts} +17 -49
  35. package/dist/zod/tempo/MultisigSimulation.d.ts.map +1 -0
  36. package/dist/zod/tempo/{MultisigWitness.js → MultisigSimulation.js} +26 -24
  37. package/dist/zod/tempo/MultisigSimulation.js.map +1 -0
  38. package/dist/zod/tempo/RpcSchemaTempo.d.ts +83 -204
  39. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  40. package/dist/zod/tempo/RpcSchemaTempo.js +19 -10
  41. package/dist/zod/tempo/RpcSchemaTempo.js.map +1 -1
  42. package/dist/zod/tempo/SignatureEnvelope.d.ts +3 -39
  43. package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
  44. package/dist/zod/tempo/SignatureEnvelope.js +4 -14
  45. package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
  46. package/dist/zod/tempo/Transaction.d.ts +18 -234
  47. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  48. package/dist/zod/tempo/TransactionRequest.d.ts +36 -192
  49. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  50. package/dist/zod/tempo/TransactionRequest.js +10 -10
  51. package/dist/zod/tempo/TransactionRequest.js.map +1 -1
  52. package/dist/zod/tempo/z.d.ts +1 -1
  53. package/dist/zod/tempo/z.d.ts.map +1 -1
  54. package/dist/zod/tempo/z.js +1 -1
  55. package/dist/zod/tempo/z.js.map +1 -1
  56. package/package.json +9 -9
  57. package/src/tempo/AuthorizationTempo.test.ts +4 -0
  58. package/src/tempo/KeyAuthorization.test-d.ts +1 -12
  59. package/src/tempo/KeyAuthorization.test.ts +44 -3
  60. package/src/tempo/KeyAuthorization.ts +3 -3
  61. package/src/tempo/MultisigOperation.test-d.ts +8 -6
  62. package/src/tempo/MultisigOperation.test.ts +236 -169
  63. package/src/tempo/MultisigOperation.ts +122 -83
  64. package/src/tempo/MultisigSimulation.test-d.ts +33 -0
  65. package/src/tempo/MultisigSimulation.test.ts +283 -0
  66. package/src/tempo/MultisigSimulation.ts +266 -0
  67. package/src/tempo/RpcSchemaTempo.test-d.ts +45 -10
  68. package/src/tempo/RpcSchemaTempo.ts +15 -6
  69. package/src/tempo/SignatureEnvelope.test-d.ts +3 -59
  70. package/src/tempo/SignatureEnvelope.test.ts +61 -51
  71. package/src/tempo/SignatureEnvelope.ts +27 -44
  72. package/src/tempo/Transaction.test.ts +61 -0
  73. package/src/tempo/TransactionRequest.test-d.ts +7 -7
  74. package/src/tempo/TransactionRequest.test.ts +129 -208
  75. package/src/tempo/TransactionRequest.ts +16 -12
  76. package/src/tempo/index.ts +4 -4
  77. package/src/tempo/multisig.e2e.test.ts +51 -1
  78. package/src/version.ts +1 -1
  79. package/src/zod/tempo/MultisigOperation.ts +0 -3
  80. package/src/zod/tempo/{MultisigWitness.ts → MultisigSimulation.ts} +39 -42
  81. package/src/zod/tempo/RpcSchemaTempo.ts +20 -10
  82. package/src/zod/tempo/SignatureEnvelope.ts +11 -35
  83. package/src/zod/tempo/TransactionRequest.ts +14 -14
  84. package/src/zod/tempo/_test/KeyAuthorization.test.ts +2 -15
  85. package/src/zod/tempo/_test/MultisigOperation.test.ts +0 -2
  86. package/src/zod/tempo/_test/MultisigSimulation.test-d.ts +13 -0
  87. package/src/zod/tempo/_test/MultisigSimulation.test.ts +78 -0
  88. package/src/zod/tempo/_test/RpcSchemaTempo.test-d.ts +19 -2
  89. package/src/zod/tempo/_test/RpcSchemaTempo.test.ts +46 -4
  90. package/src/zod/tempo/_test/SignatureEnvelope.test.ts +58 -112
  91. package/src/zod/tempo/_test/TransactionRequest.test.ts +19 -160
  92. package/src/zod/tempo/z.ts +1 -1
  93. package/dist/tempo/MultisigWitness.d.ts +0 -106
  94. package/dist/tempo/MultisigWitness.d.ts.map +0 -1
  95. package/dist/tempo/MultisigWitness.js +0 -118
  96. package/dist/tempo/MultisigWitness.js.map +0 -1
  97. package/dist/zod/tempo/MultisigWitness.d.ts.map +0 -1
  98. package/dist/zod/tempo/MultisigWitness.js.map +0 -1
  99. package/src/tempo/MultisigWitness.test-d.ts +0 -42
  100. package/src/tempo/MultisigWitness.test.ts +0 -288
  101. package/src/tempo/MultisigWitness.ts +0 -210
  102. package/src/zod/tempo/_test/MultisigWitness.test-d.ts +0 -13
  103. package/src/zod/tempo/_test/MultisigWitness.test.ts +0 -149
@@ -39,7 +39,7 @@ const config = MultisigConfig.from({
39
39
  ],
40
40
  threshold: 2,
41
41
  })
42
- const initializedConfig = MultisigConfig.from({ ...config, version: 1n })
42
+ const currentConfig = MultisigConfig.from({ ...config, version: 1n })
43
43
  const account = MultisigConfig.getAddress(config)
44
44
  const ownerSignature_1 = owners[0]!.signature
45
45
  const approval_1 = SignatureEnvelope.serialize(ownerSignature_1)
@@ -66,14 +66,14 @@ const keyAuthorization = KeyAuthorization.serialize(
66
66
 
67
67
  const transactionHash_ = MultisigConfig.getSignPayload({
68
68
  account,
69
- config: initializedConfig,
69
+ config: currentConfig,
70
70
  payload: TxEnvelopeTempo.getSignPayload(
71
71
  TxEnvelopeTempo.deserialize(transaction),
72
72
  ),
73
73
  })
74
74
  const keyAuthorizationHash = MultisigConfig.getSignPayload({
75
75
  account,
76
- config: initializedConfig,
76
+ config: currentConfig,
77
77
  payload: KeyAuthorization.getSignPayload(
78
78
  KeyAuthorization.deserialize(keyAuthorization),
79
79
  ),
@@ -82,10 +82,8 @@ const keyAuthorizationHash = MultisigConfig.getSignPayload({
82
82
  const base = {
83
83
  account,
84
84
  approvals: [approval_1],
85
- config: initializedConfig,
86
- configVersion: 1n,
85
+ config: currentConfig,
87
86
  createdAt: 1,
88
- init: false,
89
87
  signatureCount: 1,
90
88
  threshold: 2,
91
89
  updatedAt: 2,
@@ -142,13 +140,13 @@ describe('getHash', () => {
142
140
  expect({
143
141
  keyAuthorization: MultisigOperation.getHash({
144
142
  account,
145
- configVersion: 1n,
143
+ config: currentConfig,
146
144
  keyAuthorization,
147
145
  type: 'keyAuthorization',
148
146
  }),
149
147
  transaction: MultisigOperation.getHash({
150
148
  account,
151
- configVersion: 1n,
149
+ config: currentConfig,
152
150
  transaction,
153
151
  type: 'transaction',
154
152
  }),
@@ -174,7 +172,7 @@ describe('selectApprovals', () => {
174
172
  const account = MultisigConfig.getAddress(config)
175
173
  const hash = MultisigOperation.getHash({
176
174
  account,
177
- configVersion: 1n,
175
+ config: { ...config, version: 1n },
178
176
  transaction,
179
177
  type: 'transaction',
180
178
  })
@@ -247,13 +245,13 @@ describe('selectApprovals', () => {
247
245
  const account = MultisigConfig.getAddress(config)
248
246
  const hash = MultisigOperation.getHash({
249
247
  account,
250
- configVersion: 1n,
248
+ config: { ...config, version: 1n },
251
249
  transaction,
252
250
  type: 'transaction',
253
251
  })
254
252
  const childHash = MultisigConfig.getSignPayload({
255
253
  account: child,
256
- config: { version: 2n },
254
+ config: { ...childConfig, version: 2n },
257
255
  payload: hash,
258
256
  })
259
257
  const childApprovals = [
@@ -261,15 +259,6 @@ describe('selectApprovals', () => {
261
259
  signApproval(owners[2]!, childHash),
262
260
  ]
263
261
  const rootApproval = signApproval(owners[0]!, hash)
264
- const resolveConfig: MultisigOperation.selectApprovals.ResolveConfig = ({
265
- account,
266
- }) => {
267
- if (!Address.isEqual(account, child)) throw new Error('unknown account')
268
- return {
269
- config: MultisigConfig.from({ ...childConfig, version: 2n }),
270
- version: 2n,
271
- }
272
- }
273
262
  const partial = await MultisigOperation.selectApprovals({
274
263
  account,
275
264
  approvals: [
@@ -283,7 +272,6 @@ describe('selectApprovals', () => {
283
272
  ],
284
273
  config,
285
274
  hash,
286
- resolveConfig,
287
275
  })
288
276
  const complete = await MultisigOperation.selectApprovals({
289
277
  account,
@@ -300,7 +288,6 @@ describe('selectApprovals', () => {
300
288
  ],
301
289
  config,
302
290
  hash,
303
- resolveConfig,
304
291
  })
305
292
 
306
293
  expect({
@@ -344,7 +331,7 @@ describe('selectApprovals', () => {
344
331
  `)
345
332
  })
346
333
 
347
- test('rejects mismatched nested config versions', async () => {
334
+ test('rejects conflicting nested config witnesses', async () => {
348
335
  const childConfig = MultisigConfig.from({
349
336
  owners: [{ owner: owners[1]!.address, weight: 1 }],
350
337
  threshold: 1,
@@ -357,17 +344,26 @@ describe('selectApprovals', () => {
357
344
  const account = MultisigConfig.getAddress(config)
358
345
  const hash = MultisigOperation.getHash({
359
346
  account,
360
- configVersion: 1n,
347
+ config: { ...config, version: 1n },
361
348
  transaction,
362
349
  type: 'transaction',
363
350
  })
364
- const resolvedConfig = MultisigConfig.from({
351
+ const config_2 = MultisigConfig.from({
365
352
  ...childConfig,
366
353
  version: 2n,
367
354
  })
368
- const childHash = MultisigConfig.getSignPayload({
355
+ const config_3 = MultisigConfig.from({
356
+ ...childConfig,
357
+ version: 3n,
358
+ })
359
+ const childHash_2 = MultisigConfig.getSignPayload({
360
+ account: child,
361
+ config: config_2,
362
+ payload: hash,
363
+ })
364
+ const childHash_3 = MultisigConfig.getSignPayload({
369
365
  account: child,
370
- config: resolvedConfig,
366
+ config: config_3,
371
367
  payload: hash,
372
368
  })
373
369
 
@@ -377,10 +373,20 @@ describe('selectApprovals', () => {
377
373
  approvals: [
378
374
  SignatureEnvelope.serialize({
379
375
  account: child,
380
- config: resolvedConfig,
376
+ config: config_2,
381
377
  signatures: [
382
378
  SignatureEnvelope.deserialize(
383
- signApproval(owners[1]!, childHash),
379
+ signApproval(owners[1]!, childHash_2),
380
+ ),
381
+ ],
382
+ type: 'multisig',
383
+ }),
384
+ SignatureEnvelope.serialize({
385
+ account: child,
386
+ config: config_3,
387
+ signatures: [
388
+ SignatureEnvelope.deserialize(
389
+ signApproval(owners[1]!, childHash_3),
384
390
  ),
385
391
  ],
386
392
  type: 'multisig',
@@ -388,17 +394,32 @@ describe('selectApprovals', () => {
388
394
  ],
389
395
  config,
390
396
  hash,
391
- resolveConfig: () => ({ config: childConfig, version: 2n }),
392
397
  }),
393
398
  ).rejects.toThrowErrorMatchingInlineSnapshot(
394
- `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: resolved config.version must equal version for nested multisig owner 0x7888d60e9cc26c8569d394fce435c248f1e49c3b.]`,
399
+ `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: nested multisig owner 0x7888d60e9cc26c8569d394fce435c248f1e49c3b has conflicting config witnesses.]`,
400
+ )
401
+ })
402
+
403
+ test('rejects an initial root config for another account', async () => {
404
+ await expect(
405
+ MultisigOperation.selectApprovals({
406
+ account,
407
+ approvals: [],
408
+ config: MultisigConfig.from({
409
+ ...config,
410
+ salt: `0x${'ff'.repeat(32)}`,
411
+ }),
412
+ hash: transactionHash_,
413
+ }),
414
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
415
+ `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: initial config does not derive the root multisig account.]`,
395
416
  )
396
417
  })
397
418
 
398
419
  test('rejects invalid and non-owner approvals', async () => {
399
420
  const hash = MultisigOperation.getHash({
400
421
  account,
401
- configVersion: 1n,
422
+ config: currentConfig,
402
423
  transaction,
403
424
  type: 'transaction',
404
425
  })
@@ -430,7 +451,7 @@ describe('selectApprovals', () => {
430
451
  )
431
452
  })
432
453
 
433
- test('requires a resolver for nested owners', async () => {
454
+ test('reads current nested config witnesses from approvals', async () => {
434
455
  const childConfig = MultisigConfig.from({
435
456
  owners: [{ owner: owners[1]!.address, weight: 1 }],
436
457
  threshold: 1,
@@ -443,36 +464,49 @@ describe('selectApprovals', () => {
443
464
  const account = MultisigConfig.getAddress(config)
444
465
  const hash = MultisigOperation.getHash({
445
466
  account,
446
- configVersion: 1n,
467
+ config: { ...config, version: 1n },
447
468
  transaction,
448
469
  type: 'transaction',
449
470
  })
450
471
  const childHash = MultisigConfig.getSignPayload({
451
472
  account: child,
452
- config: { version: 1n },
473
+ config: { ...childConfig, version: 1n },
453
474
  payload: hash,
454
475
  })
455
476
 
456
- await expect(
457
- MultisigOperation.selectApprovals({
458
- account,
459
- approvals: [
460
- SignatureEnvelope.serialize({
461
- account: child,
462
- config: MultisigConfig.from({ ...childConfig, version: 1n }),
463
- signatures: [
464
- SignatureEnvelope.deserialize(
465
- signApproval(owners[1]!, childHash),
466
- ),
467
- ],
468
- type: 'multisig',
469
- }),
477
+ const selection = await MultisigOperation.selectApprovals({
478
+ account,
479
+ approvals: [
480
+ SignatureEnvelope.serialize({
481
+ account: child,
482
+ config: MultisigConfig.from({ ...childConfig, version: 1n }),
483
+ signatures: [
484
+ SignatureEnvelope.deserialize(signApproval(owners[1]!, childHash)),
485
+ ],
486
+ type: 'multisig',
487
+ }),
488
+ ],
489
+ config,
490
+ hash,
491
+ })
492
+ expect(selection).toMatchInlineSnapshot(
493
+ {
494
+ approvals: [expect.any(String)],
495
+ selectedApprovals: [expect.any(String)],
496
+ },
497
+ `
498
+ {
499
+ "approvals": [
500
+ Any<String>,
470
501
  ],
471
- config,
472
- hash,
473
- }),
474
- ).rejects.toThrowErrorMatchingInlineSnapshot(
475
- `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: nested multisig owner 0x7888d60e9cc26c8569d394fce435c248f1e49c3b requires a config resolver.]`,
502
+ "selectedApprovals": [
503
+ Any<String>,
504
+ ],
505
+ "signatureCount": 1,
506
+ "threshold": 1,
507
+ "weight": 1,
508
+ }
509
+ `,
476
510
  )
477
511
  })
478
512
 
@@ -492,7 +526,7 @@ describe('selectApprovals', () => {
492
526
  const account = MultisigConfig.getAddress(config)
493
527
  const hash = MultisigOperation.getHash({
494
528
  account,
495
- configVersion: 1n,
529
+ config: { ...config, version: 1n },
496
530
  transaction,
497
531
  type: 'transaction',
498
532
  })
@@ -534,7 +568,6 @@ describe('selectApprovals', () => {
534
568
  ],
535
569
  config,
536
570
  hash,
537
- resolveConfig: () => ({ config: childConfig, version: 0n }),
538
571
  })
539
572
  expect({
540
573
  signatureCount: selection.signatureCount,
@@ -556,7 +589,7 @@ describe('selectApprovals', () => {
556
589
  })
557
590
  const hash = MultisigOperation.getHash({
558
591
  account,
559
- configVersion: 2n,
592
+ config: { ...config, version: 2n },
560
593
  transaction,
561
594
  type: 'transaction',
562
595
  })
@@ -598,18 +631,18 @@ describe('selectApprovals', () => {
598
631
  const account = MultisigConfig.getAddress(config)
599
632
  const hash = MultisigOperation.getHash({
600
633
  account,
601
- configVersion: 1n,
634
+ config: { ...config, version: 1n },
602
635
  transaction,
603
636
  type: 'transaction',
604
637
  })
605
638
  const childHash = MultisigConfig.getSignPayload({
606
639
  account: child,
607
- config: { version: 1n },
640
+ config: { ...childConfig, version: 1n },
608
641
  payload: hash,
609
642
  })
610
643
  const grandchildHash = MultisigConfig.getSignPayload({
611
644
  account: grandchild,
612
- config: { version: 1n },
645
+ config: { ...grandchildConfig, version: 1n },
613
646
  payload: childHash,
614
647
  })
615
648
 
@@ -640,20 +673,6 @@ describe('selectApprovals', () => {
640
673
  ],
641
674
  config,
642
675
  hash,
643
- resolveConfig: ({ account }) => {
644
- if (Address.isEqual(account, child))
645
- return {
646
- config: MultisigConfig.from({ ...childConfig, version: 1n }),
647
- version: 1n,
648
- }
649
- return {
650
- config: MultisigConfig.from({
651
- ...grandchildConfig,
652
- version: 1n,
653
- }),
654
- version: 1n,
655
- }
656
- },
657
676
  }),
658
677
  ).rejects.toThrowErrorMatchingInlineSnapshot(
659
678
  `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: nested multisig owner 0xf529c8f6b2b4c72102af4cfe5eeb55b7d45dede2 is invalid.]`,
@@ -661,15 +680,107 @@ describe('selectApprovals', () => {
661
680
  })
662
681
  })
663
682
 
683
+ describe('serializeKeyAuthorization', () => {
684
+ test('current and initial authorizations', async () => {
685
+ const results = []
686
+ for (const applicableConfig of [currentConfig, config]) {
687
+ const hash = MultisigOperation.getHash({
688
+ account,
689
+ config: applicableConfig,
690
+ keyAuthorization,
691
+ type: 'keyAuthorization',
692
+ })
693
+ const selection = await MultisigOperation.selectApprovals({
694
+ account,
695
+ approvals: [
696
+ signApproval(owners[1]!, hash),
697
+ signApproval(owners[0]!, hash),
698
+ ],
699
+ config: applicableConfig,
700
+ hash,
701
+ })
702
+ const serialized = MultisigOperation.serializeKeyAuthorization(
703
+ keyAuthorization,
704
+ {
705
+ account,
706
+ approvals: selection.selectedApprovals,
707
+ config: applicableConfig,
708
+ },
709
+ )
710
+ const value = KeyAuthorization.deserialize(serialized)
711
+ results.push({
712
+ account:
713
+ value.signature?.type === 'multisig'
714
+ ? value.signature.account
715
+ : undefined,
716
+ hash: Hash.keccak256(serialized),
717
+ signatureCount:
718
+ value.signature?.type === 'multisig'
719
+ ? value.signature.signatures.length
720
+ : 0,
721
+ version:
722
+ value.signature?.type === 'multisig'
723
+ ? value.signature.config.version
724
+ : undefined,
725
+ })
726
+ }
727
+
728
+ expect(results).toMatchInlineSnapshot(`
729
+ [
730
+ {
731
+ "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
732
+ "hash": "0x14b3a60f7c3120e3983b1f6e085ab5b234e71f58f0a4f39d19a5ff64b89a2afe",
733
+ "signatureCount": 2,
734
+ "version": 1n,
735
+ },
736
+ {
737
+ "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
738
+ "hash": "0xbfdc90810a0634f413e627bdefea88ae8c42ed41d6670a70fd1d7574aedda2a4",
739
+ "signatureCount": 2,
740
+ "version": 0n,
741
+ },
742
+ ]
743
+ `)
744
+ })
745
+
746
+ test('rejects a signed authorization', async () => {
747
+ const selection = await MultisigOperation.selectApprovals({
748
+ account,
749
+ approvals: [
750
+ signApproval(owners[0]!, keyAuthorizationHash),
751
+ signApproval(owners[1]!, keyAuthorizationHash),
752
+ ],
753
+ config: currentConfig,
754
+ hash: keyAuthorizationHash,
755
+ })
756
+ const signed = MultisigOperation.serializeKeyAuthorization(
757
+ keyAuthorization,
758
+ {
759
+ account,
760
+ approvals: selection.selectedApprovals,
761
+ config: currentConfig,
762
+ },
763
+ )
764
+
765
+ expect(() =>
766
+ MultisigOperation.serializeKeyAuthorization(signed, {
767
+ account,
768
+ approvals: selection.selectedApprovals,
769
+ config: currentConfig,
770
+ }),
771
+ ).toThrowErrorMatchingInlineSnapshot(
772
+ `[MultisigOperation.InvalidOperationError: Invalid multisig operation: keyAuthorization must not contain a signature.]`,
773
+ )
774
+ })
775
+ })
776
+
664
777
  describe('serializeTransaction', () => {
665
- test('initialized and bootstrap transactions', async () => {
778
+ test('current and initial transactions', async () => {
666
779
  const results = []
667
- for (const init of [false, true]) {
668
- const configVersion = init ? 0n : 1n
669
- const applicableConfig = init ? config : initializedConfig
780
+ for (const applicableConfig of [currentConfig, config]) {
670
781
  const hash = MultisigOperation.getHash({
671
782
  account,
672
- configVersion,
783
+ config: applicableConfig,
673
784
  transaction,
674
785
  type: 'transaction',
675
786
  })
@@ -686,10 +797,8 @@ describe('serializeTransaction', () => {
686
797
  account,
687
798
  approvals: selection.approvals,
688
799
  config: applicableConfig,
689
- configVersion,
690
800
  createdAt: 1,
691
801
  hash,
692
- init,
693
802
  signatureCount: selection.signatureCount,
694
803
  status: 'pending',
695
804
  threshold: selection.threshold,
@@ -704,7 +813,7 @@ describe('serializeTransaction', () => {
704
813
  const value = TxEnvelopeTempo.deserialize(serialized)
705
814
  results.push({
706
815
  account: value.signature?.account,
707
- configVersion:
816
+ version:
708
817
  value.signature?.type === 'multisig'
709
818
  ? value.signature.config.version
710
819
  : undefined,
@@ -721,17 +830,17 @@ describe('serializeTransaction', () => {
721
830
  [
722
831
  {
723
832
  "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
724
- "configVersion": 1n,
725
833
  "hash": "0x8309740edaf304284186f7bcfe4527745cd4eb48e7441795ebdd970798091f8f",
726
834
  "signatureCount": 2,
727
835
  "type": "0x76",
836
+ "version": 1n,
728
837
  },
729
838
  {
730
839
  "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
731
- "configVersion": 0n,
732
840
  "hash": "0x636af84d8445d87cbcd33039d5a3a2274a5911036b1b7ceb740ac41e2f638611",
733
841
  "signatureCount": 2,
734
842
  "type": "0x76",
843
+ "version": 0n,
735
844
  },
736
845
  ]
737
846
  `)
@@ -763,7 +872,7 @@ describe('serializeTransaction', () => {
763
872
  for (const transaction of transactions) {
764
873
  const hash = MultisigOperation.getHash({
765
874
  account,
766
- configVersion: 1n,
875
+ config: currentConfig,
767
876
  transaction,
768
877
  type: 'transaction',
769
878
  })
@@ -773,18 +882,16 @@ describe('serializeTransaction', () => {
773
882
  signApproval(owners[0]!, hash),
774
883
  signApproval(owners[1]!, hash),
775
884
  ],
776
- config: initializedConfig,
885
+ config: currentConfig,
777
886
  hash,
778
887
  })
779
888
  const serialized = MultisigOperation.serializeTransaction(
780
889
  MultisigOperation.from({
781
890
  account,
782
891
  approvals: selection.approvals,
783
- config: initializedConfig,
784
- configVersion: 1n,
892
+ config: currentConfig,
785
893
  createdAt: 1,
786
894
  hash,
787
- init: false,
788
895
  signatureCount: selection.signatureCount,
789
896
  status: 'pending',
790
897
  threshold: selection.threshold,
@@ -832,7 +939,7 @@ describe('serializeTransaction', () => {
832
939
  test('rejects an approval not retained by the operation', async () => {
833
940
  const hash = MultisigOperation.getHash({
834
941
  account,
835
- configVersion: 1n,
942
+ config: currentConfig,
836
943
  transaction,
837
944
  type: 'transaction',
838
945
  })
@@ -841,17 +948,15 @@ describe('serializeTransaction', () => {
841
948
  const selection = await MultisigOperation.selectApprovals({
842
949
  account,
843
950
  approvals: [approval_1],
844
- config: initializedConfig,
951
+ config: currentConfig,
845
952
  hash,
846
953
  })
847
954
  const operation = MultisigOperation.from({
848
955
  account,
849
956
  approvals: selection.approvals,
850
- config: initializedConfig,
851
- configVersion: 1n,
957
+ config: currentConfig,
852
958
  createdAt: 1,
853
959
  hash,
854
- init: false,
855
960
  signatureCount: selection.signatureCount,
856
961
  status: 'pending',
857
962
  threshold: selection.threshold,
@@ -914,10 +1019,8 @@ describe('from', () => {
914
1019
  "threshold": 2,
915
1020
  "version": 1n,
916
1021
  },
917
- "configVersion": 1n,
918
1022
  "createdAt": 1,
919
1023
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
920
- "init": false,
921
1024
  "signatureCount": 1,
922
1025
  "status": "pending",
923
1026
  "threshold": 2,
@@ -947,11 +1050,9 @@ describe('from', () => {
947
1050
  "threshold": 2,
948
1051
  "version": 1n,
949
1052
  },
950
- "configVersion": 1n,
951
1053
  "createdAt": 1,
952
1054
  "expiresAt": 10,
953
1055
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
954
- "init": false,
955
1056
  "signatureCount": 2,
956
1057
  "status": "submitting",
957
1058
  "submissionId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -982,10 +1083,8 @@ describe('from', () => {
982
1083
  "threshold": 2,
983
1084
  "version": 1n,
984
1085
  },
985
- "configVersion": 1n,
986
1086
  "createdAt": 1,
987
1087
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
988
- "init": false,
989
1088
  "signatureCount": 2,
990
1089
  "status": "success",
991
1090
  "threshold": 2,
@@ -1011,7 +1110,7 @@ describe('from', () => {
1011
1110
  ...transactionPending,
1012
1111
  hash: MultisigConfig.getSignPayload({
1013
1112
  account,
1014
- config: initializedConfig,
1113
+ config: currentConfig,
1015
1114
  payload: TxEnvelopeTempo.getSignPayload(
1016
1115
  TxEnvelopeTempo.deserialize(
1017
1116
  Hex.concat(
@@ -1050,10 +1149,8 @@ describe('from', () => {
1050
1149
  "threshold": 2,
1051
1150
  "version": 1n,
1052
1151
  },
1053
- "configVersion": 1n,
1054
1152
  "createdAt": 1,
1055
1153
  "hash": Any<String>,
1056
- "init": false,
1057
1154
  "signatureCount": 1,
1058
1155
  "status": "pending",
1059
1156
  "threshold": 2,
@@ -1083,7 +1180,7 @@ describe('from', () => {
1083
1180
  ...transactionPending,
1084
1181
  hash: MultisigConfig.getSignPayload({
1085
1182
  account,
1086
- config: initializedConfig,
1183
+ config: currentConfig,
1087
1184
  payload: TxEnvelopeTempo.getSignPayload(
1088
1185
  TxEnvelopeTempo.deserialize(
1089
1186
  Hex.concat(
@@ -1099,11 +1196,10 @@ describe('from', () => {
1099
1196
  expect(operation.transaction).toBe(transaction)
1100
1197
  })
1101
1198
 
1102
- test('bootstrap transaction', () => {
1199
+ test('initial transaction', () => {
1103
1200
  const operation = MultisigOperation.from({
1104
1201
  ...transactionPending,
1105
1202
  config,
1106
- configVersion: 0n,
1107
1203
  hash: MultisigConfig.getSignPayload({
1108
1204
  account,
1109
1205
  config,
@@ -1111,7 +1207,6 @@ describe('from', () => {
1111
1207
  TxEnvelopeTempo.deserialize(transaction),
1112
1208
  ),
1113
1209
  }),
1114
- init: true,
1115
1210
  })
1116
1211
 
1117
1212
  expect(operation).toMatchInlineSnapshot(
@@ -1140,10 +1235,8 @@ describe('from', () => {
1140
1235
  "threshold": 2,
1141
1236
  "version": 0n,
1142
1237
  },
1143
- "configVersion": 0n,
1144
1238
  "createdAt": 1,
1145
1239
  "hash": Any<String>,
1146
- "init": true,
1147
1240
  "signatureCount": 1,
1148
1241
  "status": "pending",
1149
1242
  "threshold": 2,
@@ -1156,31 +1249,6 @@ describe('from', () => {
1156
1249
  )
1157
1250
  })
1158
1251
 
1159
- test('initialized transaction at config version zero', () => {
1160
- const operation = MultisigOperation.from({
1161
- ...transactionPending,
1162
- config,
1163
- configVersion: 0n,
1164
- hash: MultisigConfig.getSignPayload({
1165
- account,
1166
- config,
1167
- payload: TxEnvelopeTempo.getSignPayload(
1168
- TxEnvelopeTempo.deserialize(transaction),
1169
- ),
1170
- }),
1171
- })
1172
-
1173
- expect({
1174
- configVersion: operation.configVersion,
1175
- init: operation.init,
1176
- }).toMatchInlineSnapshot(`
1177
- {
1178
- "configVersion": 0n,
1179
- "init": false,
1180
- }
1181
- `)
1182
- })
1183
-
1184
1252
  test('key authorization states', () => {
1185
1253
  const pending = MultisigOperation.from(keyAuthorizationPending)
1186
1254
  const authorization = KeyAuthorization.deserialize(keyAuthorization)
@@ -1191,7 +1259,7 @@ describe('from', () => {
1191
1259
  KeyAuthorization.from(authorization, {
1192
1260
  signature: {
1193
1261
  account,
1194
- config: initializedConfig,
1262
+ config: currentConfig,
1195
1263
  signatures: [
1196
1264
  SignatureEnvelope.deserialize(approval_1),
1197
1265
  SignatureEnvelope.deserialize(approval_2),
@@ -1227,10 +1295,8 @@ describe('from', () => {
1227
1295
  "threshold": 2,
1228
1296
  "version": 1n,
1229
1297
  },
1230
- "configVersion": 1n,
1231
1298
  "createdAt": 1,
1232
1299
  "hash": "0xf6995eb69c12c03d3d13b357abf7cac22b4effe52fba8ff02e5aef26161f77a0",
1233
- "init": false,
1234
1300
  "keyAuthorization": "0xf838f782107980943333333333333333333333333333333333333333846b49d2008080808094f81b7763d3a6876195d780865bd783dbd97dd36e",
1235
1301
  "signatureCount": 1,
1236
1302
  "status": "pending",
@@ -1260,10 +1326,8 @@ describe('from', () => {
1260
1326
  "threshold": 2,
1261
1327
  "version": 1n,
1262
1328
  },
1263
- "configVersion": 1n,
1264
1329
  "createdAt": 1,
1265
1330
  "hash": "0xf6995eb69c12c03d3d13b357abf7cac22b4effe52fba8ff02e5aef26161f77a0",
1266
- "init": false,
1267
1331
  "keyAuthorization": "0xf901b3f782107980943333333333333333333333333333333333333333846b49d2008080808094f81b7763d3a6876195d780865bd783dbd97dd36eb9017805f9017494f81b7763d3a6876195d780865bd783dbd97dd36ef852a000000000000000000000000000000000000000000000000000000000000000000102eed69407e1ed8ea0e9601e5546b0a03aed683df360140701d694288f0cd85005f34168f731a468aef268c2f9456f01f90108b88201000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000065ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d503200b88201000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000047cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc4766997807775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d100",
1268
1332
  "signatureCount": 2,
1269
1333
  "status": "success",
@@ -1276,7 +1340,7 @@ describe('from', () => {
1276
1340
  `)
1277
1341
  })
1278
1342
 
1279
- test('bootstrap key authorization', () => {
1343
+ test('initial key authorization', () => {
1280
1344
  const authorization = KeyAuthorization.deserialize(keyAuthorization)
1281
1345
  const keyAuthorization_ = KeyAuthorization.serialize(
1282
1346
  KeyAuthorization.from(authorization, {
@@ -1295,13 +1359,11 @@ describe('from', () => {
1295
1359
  ...keyAuthorizationPending,
1296
1360
  approvals: [approval_1, approval_2],
1297
1361
  config,
1298
- configVersion: 0n,
1299
1362
  hash: MultisigConfig.getSignPayload({
1300
1363
  account,
1301
1364
  config,
1302
1365
  payload: KeyAuthorization.getSignPayload(authorization),
1303
1366
  }),
1304
- init: true,
1305
1367
  keyAuthorization: keyAuthorization_,
1306
1368
  signatureCount: 2,
1307
1369
  status: 'success',
@@ -1335,10 +1397,8 @@ describe('from', () => {
1335
1397
  "threshold": 2,
1336
1398
  "version": 0n,
1337
1399
  },
1338
- "configVersion": 0n,
1339
1400
  "createdAt": 1,
1340
1401
  "hash": Any<String>,
1341
- "init": true,
1342
1402
  "keyAuthorization": Any<String>,
1343
1403
  "signatureCount": 2,
1344
1404
  "status": "success",
@@ -1382,10 +1442,8 @@ describe('RPC conversion', () => {
1382
1442
  "threshold": 2,
1383
1443
  "version": "0x1",
1384
1444
  },
1385
- "configVersion": "0x1",
1386
1445
  "createdAt": 1,
1387
1446
  "hash": "0xf6995eb69c12c03d3d13b357abf7cac22b4effe52fba8ff02e5aef26161f77a0",
1388
- "init": false,
1389
1447
  "keyAuthorization": "0xf838f782107980943333333333333333333333333333333333333333846b49d2008080808094f81b7763d3a6876195d780865bd783dbd97dd36e",
1390
1448
  "signatureCount": 1,
1391
1449
  "status": "pending",
@@ -1414,10 +1472,8 @@ describe('RPC conversion', () => {
1414
1472
  "threshold": 2,
1415
1473
  "version": "0x1",
1416
1474
  },
1417
- "configVersion": "0x1",
1418
1475
  "createdAt": 1,
1419
1476
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
1420
- "init": false,
1421
1477
  "signatureCount": 1,
1422
1478
  "status": "pending",
1423
1479
  "threshold": 2,
@@ -1550,7 +1606,7 @@ describe('validation', () => {
1550
1606
  account: '0x0000000000000000000000000000000000000000',
1551
1607
  hash: MultisigConfig.getSignPayload({
1552
1608
  account: '0x0000000000000000000000000000000000000000',
1553
- config: initializedConfig,
1609
+ config: currentConfig,
1554
1610
  payload: TxEnvelopeTempo.getSignPayload(
1555
1611
  TxEnvelopeTempo.deserialize(transaction),
1556
1612
  ),
@@ -1617,7 +1673,7 @@ describe('validation', () => {
1617
1673
  },
1618
1674
  },
1619
1675
  {
1620
- name: 'nested bootstrap owner approval',
1676
+ name: 'nested non-owner approval',
1621
1677
  operation: {
1622
1678
  ...transactionPending,
1623
1679
  approvals: [
@@ -1630,35 +1686,48 @@ describe('validation', () => {
1630
1686
  ],
1631
1687
  },
1632
1688
  },
1633
- {
1634
- name: 'bootstrap with initialized version',
1635
- operation: { ...transactionPending, init: true },
1636
- },
1637
1689
  ])('rejects $name', ({ operation }) => {
1638
1690
  expect(() =>
1639
1691
  MultisigOperation.from(operation as MultisigOperation.Operation),
1640
1692
  ).toThrowError(MultisigOperation.InvalidOperationError)
1641
1693
  })
1642
1694
 
1643
- test('rejects mismatched config versions', () => {
1695
+ test('rejects an initial config for another account', () => {
1696
+ const config = MultisigConfig.from({
1697
+ ...transactionPending.config,
1698
+ salt: `0x${'ff'.repeat(32)}`,
1699
+ version: 0n,
1700
+ })
1644
1701
  expect(() =>
1645
1702
  MultisigOperation.from({
1646
1703
  ...transactionPending,
1647
- config: { ...initializedConfig, version: 2n },
1704
+ config,
1705
+ hash: MultisigConfig.getSignPayload({
1706
+ account,
1707
+ config,
1708
+ payload: TxEnvelopeTempo.getSignPayload(
1709
+ TxEnvelopeTempo.deserialize(transaction),
1710
+ ),
1711
+ }),
1648
1712
  }),
1649
1713
  ).toThrowErrorMatchingInlineSnapshot(
1650
- `[MultisigOperation.InvalidOperationError: Invalid multisig operation: config.version must equal configVersion.]`,
1714
+ `
1715
+ [MultisigOperation.InvalidOperationError: Invalid multisig operation.
1716
+
1717
+ Details: Invalid native multisig owner approval: initial multisig config does not derive account.]
1718
+ `,
1651
1719
  )
1652
1720
  })
1653
1721
 
1654
1722
  test('rejects noncanonical RPC quantities', () => {
1723
+ const operation = MultisigOperation.toRpc(transactionPending)
1655
1724
  expect(() =>
1656
1725
  MultisigOperation.fromRpc({
1657
- ...MultisigOperation.toRpc(transactionPending),
1658
- configVersion: '0x01',
1726
+ ...operation,
1727
+ config: { ...operation.config, version: '0x01' },
1659
1728
  }),
1660
1729
  ).toThrowError(
1661
- 'Invalid multisig operation: configVersion must use canonical quantity encoding.',
1730
+ 'Invalid multisig operation: config.version must use canonical quantity encoding.',
1662
1731
  )
1663
1732
  })
1664
1733
 
@@ -1671,7 +1740,7 @@ describe('validation', () => {
1671
1740
  KeyAuthorization.from(authorization, {
1672
1741
  signature: {
1673
1742
  account,
1674
- config: initializedConfig,
1743
+ config: currentConfig,
1675
1744
  signatures: [
1676
1745
  SignatureEnvelope.deserialize(approval_1),
1677
1746
  SignatureEnvelope.deserialize(approval_3),
@@ -1695,7 +1764,7 @@ describe('validation', () => {
1695
1764
  const signatures = [
1696
1765
  ...SignatureEnvelope.sortMultisigApprovals({
1697
1766
  account,
1698
- config: initializedConfig,
1767
+ config: currentConfig,
1699
1768
  payload: KeyAuthorization.getSignPayload(authorization),
1700
1769
  signatures: [
1701
1770
  SignatureEnvelope.deserialize(approval_1),
@@ -1710,7 +1779,7 @@ describe('validation', () => {
1710
1779
  KeyAuthorization.from(authorization, {
1711
1780
  signature: {
1712
1781
  account,
1713
- config: initializedConfig,
1782
+ config: currentConfig,
1714
1783
  signatures,
1715
1784
  type: 'multisig',
1716
1785
  },
@@ -1735,7 +1804,7 @@ describe('validation', () => {
1735
1804
  KeyAuthorization.from(authorization, {
1736
1805
  signature: {
1737
1806
  account,
1738
- config: initializedConfig,
1807
+ config: currentConfig,
1739
1808
  signatures: [
1740
1809
  SignatureEnvelope.deserialize(approval_1),
1741
1810
  SignatureEnvelope.deserialize(approval_1),
@@ -1784,7 +1853,7 @@ describe('validation', () => {
1784
1853
  })
1785
1854
  const selected = SignatureEnvelope.sortMultisigApprovals({
1786
1855
  account,
1787
- config: initializedConfig,
1856
+ config: currentConfig,
1788
1857
  payload: KeyAuthorization.getSignPayload(authorization),
1789
1858
  signatures: [selectedNested, SignatureEnvelope.deserialize(approval_2)],
1790
1859
  })
@@ -1795,7 +1864,7 @@ describe('validation', () => {
1795
1864
  KeyAuthorization.from(authorization, {
1796
1865
  signature: {
1797
1866
  account,
1798
- config: initializedConfig,
1867
+ config: currentConfig,
1799
1868
  signatures: selected,
1800
1869
  type: 'multisig',
1801
1870
  },
@@ -1811,7 +1880,7 @@ describe('validation', () => {
1811
1880
  )
1812
1881
  })
1813
1882
 
1814
- test('accepts case-insensitive bootstrap configs', () => {
1883
+ test('accepts case-insensitive initial configs', () => {
1815
1884
  const config = MultisigConfig.from({
1816
1885
  owners: [
1817
1886
  {
@@ -1852,14 +1921,12 @@ describe('validation', () => {
1852
1921
  account,
1853
1922
  approvals,
1854
1923
  config,
1855
- configVersion: 0n,
1856
1924
  createdAt: 1,
1857
1925
  hash: MultisigConfig.getSignPayload({
1858
1926
  account,
1859
1927
  config,
1860
1928
  payload: KeyAuthorization.getSignPayload(authorization),
1861
1929
  }),
1862
- init: true,
1863
1930
  keyAuthorization: KeyAuthorization.serialize(
1864
1931
  KeyAuthorization.from(authorization, {
1865
1932
  signature: {