ox 0.14.40 → 0.14.42

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.
@@ -36,7 +36,7 @@ const config = MultisigConfig.from({
36
36
  ],
37
37
  threshold: 2,
38
38
  })
39
- const initializedConfig = MultisigConfig.from({ ...config, version: 1n })
39
+ const currentConfig = MultisigConfig.from({ ...config, version: 1n })
40
40
  const account = MultisigConfig.getAddress(config)
41
41
  const ownerSignature_1 = owners[0]!.signature
42
42
  const approval_1 = SignatureEnvelope.serialize(ownerSignature_1)
@@ -63,14 +63,14 @@ const keyAuthorization = KeyAuthorization.serialize(
63
63
 
64
64
  const transactionHash_ = MultisigConfig.getSignPayload({
65
65
  account,
66
- config: initializedConfig,
66
+ config: currentConfig,
67
67
  payload: TxEnvelopeTempo.getSignPayload(
68
68
  TxEnvelopeTempo.deserialize(transaction),
69
69
  ),
70
70
  })
71
71
  const keyAuthorizationHash = MultisigConfig.getSignPayload({
72
72
  account,
73
- config: initializedConfig,
73
+ config: currentConfig,
74
74
  payload: KeyAuthorization.getSignPayload(
75
75
  KeyAuthorization.deserialize(keyAuthorization),
76
76
  ),
@@ -79,10 +79,8 @@ const keyAuthorizationHash = MultisigConfig.getSignPayload({
79
79
  const base = {
80
80
  account,
81
81
  approvals: [approval_1],
82
- config: initializedConfig,
83
- configVersion: 1n,
82
+ config: currentConfig,
84
83
  createdAt: 1,
85
- init: false,
86
84
  signatureCount: 1,
87
85
  threshold: 2,
88
86
  updatedAt: 2,
@@ -139,13 +137,13 @@ describe('getHash', () => {
139
137
  expect({
140
138
  keyAuthorization: MultisigOperation.getHash({
141
139
  account,
142
- configVersion: 1n,
140
+ config: currentConfig,
143
141
  keyAuthorization,
144
142
  type: 'keyAuthorization',
145
143
  }),
146
144
  transaction: MultisigOperation.getHash({
147
145
  account,
148
- configVersion: 1n,
146
+ config: currentConfig,
149
147
  transaction,
150
148
  type: 'transaction',
151
149
  }),
@@ -171,7 +169,7 @@ describe('selectApprovals', () => {
171
169
  const account = MultisigConfig.getAddress(config)
172
170
  const hash = MultisigOperation.getHash({
173
171
  account,
174
- configVersion: 1n,
172
+ config: { ...config, version: 1n },
175
173
  transaction,
176
174
  type: 'transaction',
177
175
  })
@@ -244,13 +242,13 @@ describe('selectApprovals', () => {
244
242
  const account = MultisigConfig.getAddress(config)
245
243
  const hash = MultisigOperation.getHash({
246
244
  account,
247
- configVersion: 1n,
245
+ config: { ...config, version: 1n },
248
246
  transaction,
249
247
  type: 'transaction',
250
248
  })
251
249
  const childHash = MultisigConfig.getSignPayload({
252
250
  account: child,
253
- config: { version: 2n },
251
+ config: { ...childConfig, version: 2n },
254
252
  payload: hash,
255
253
  })
256
254
  const childApprovals = [
@@ -258,15 +256,6 @@ describe('selectApprovals', () => {
258
256
  signApproval(owners[2]!, childHash),
259
257
  ]
260
258
  const rootApproval = signApproval(owners[0]!, hash)
261
- const resolveConfig: MultisigOperation.selectApprovals.ResolveConfig = ({
262
- account,
263
- }) => {
264
- if (!Address.isEqual(account, child)) throw new Error('unknown account')
265
- return {
266
- config: MultisigConfig.from({ ...childConfig, version: 2n }),
267
- version: 2n,
268
- }
269
- }
270
259
  const partial = await MultisigOperation.selectApprovals({
271
260
  account,
272
261
  approvals: [
@@ -280,7 +269,6 @@ describe('selectApprovals', () => {
280
269
  ],
281
270
  config,
282
271
  hash,
283
- resolveConfig,
284
272
  })
285
273
  const complete = await MultisigOperation.selectApprovals({
286
274
  account,
@@ -297,7 +285,6 @@ describe('selectApprovals', () => {
297
285
  ],
298
286
  config,
299
287
  hash,
300
- resolveConfig,
301
288
  })
302
289
 
303
290
  expect({
@@ -341,7 +328,7 @@ describe('selectApprovals', () => {
341
328
  `)
342
329
  })
343
330
 
344
- test('rejects mismatched nested config versions', async () => {
331
+ test('rejects conflicting nested config witnesses', async () => {
345
332
  const childConfig = MultisigConfig.from({
346
333
  owners: [{ owner: owners[1]!.address, weight: 1 }],
347
334
  threshold: 1,
@@ -354,17 +341,26 @@ describe('selectApprovals', () => {
354
341
  const account = MultisigConfig.getAddress(config)
355
342
  const hash = MultisigOperation.getHash({
356
343
  account,
357
- configVersion: 1n,
344
+ config: { ...config, version: 1n },
358
345
  transaction,
359
346
  type: 'transaction',
360
347
  })
361
- const resolvedConfig = MultisigConfig.from({
348
+ const config_2 = MultisigConfig.from({
362
349
  ...childConfig,
363
350
  version: 2n,
364
351
  })
365
- const childHash = MultisigConfig.getSignPayload({
352
+ const config_3 = MultisigConfig.from({
353
+ ...childConfig,
354
+ version: 3n,
355
+ })
356
+ const childHash_2 = MultisigConfig.getSignPayload({
357
+ account: child,
358
+ config: config_2,
359
+ payload: hash,
360
+ })
361
+ const childHash_3 = MultisigConfig.getSignPayload({
366
362
  account: child,
367
- config: resolvedConfig,
363
+ config: config_3,
368
364
  payload: hash,
369
365
  })
370
366
 
@@ -374,10 +370,20 @@ describe('selectApprovals', () => {
374
370
  approvals: [
375
371
  SignatureEnvelope.serialize({
376
372
  account: child,
377
- config: resolvedConfig,
373
+ config: config_2,
378
374
  signatures: [
379
375
  SignatureEnvelope.deserialize(
380
- signApproval(owners[1]!, childHash),
376
+ signApproval(owners[1]!, childHash_2),
377
+ ),
378
+ ],
379
+ type: 'multisig',
380
+ }),
381
+ SignatureEnvelope.serialize({
382
+ account: child,
383
+ config: config_3,
384
+ signatures: [
385
+ SignatureEnvelope.deserialize(
386
+ signApproval(owners[1]!, childHash_3),
381
387
  ),
382
388
  ],
383
389
  type: 'multisig',
@@ -385,17 +391,32 @@ describe('selectApprovals', () => {
385
391
  ],
386
392
  config,
387
393
  hash,
388
- resolveConfig: () => ({ config: childConfig, version: 2n }),
389
394
  }),
390
395
  ).rejects.toThrowErrorMatchingInlineSnapshot(
391
- `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: resolved config.version must equal version for nested multisig owner 0x7888d60e9cc26c8569d394fce435c248f1e49c3b.]`,
396
+ `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: nested multisig owner 0x7888d60e9cc26c8569d394fce435c248f1e49c3b has conflicting config witnesses.]`,
397
+ )
398
+ })
399
+
400
+ test('rejects an initial root config for another account', async () => {
401
+ await expect(
402
+ MultisigOperation.selectApprovals({
403
+ account,
404
+ approvals: [],
405
+ config: MultisigConfig.from({
406
+ ...config,
407
+ salt: `0x${'ff'.repeat(32)}`,
408
+ }),
409
+ hash: transactionHash_,
410
+ }),
411
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
412
+ `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: initial config does not derive the root multisig account.]`,
392
413
  )
393
414
  })
394
415
 
395
416
  test('rejects invalid and non-owner approvals', async () => {
396
417
  const hash = MultisigOperation.getHash({
397
418
  account,
398
- configVersion: 1n,
419
+ config: currentConfig,
399
420
  transaction,
400
421
  type: 'transaction',
401
422
  })
@@ -427,7 +448,7 @@ describe('selectApprovals', () => {
427
448
  )
428
449
  })
429
450
 
430
- test('requires a resolver for nested owners', async () => {
451
+ test('reads current nested config witnesses from approvals', async () => {
431
452
  const childConfig = MultisigConfig.from({
432
453
  owners: [{ owner: owners[1]!.address, weight: 1 }],
433
454
  threshold: 1,
@@ -440,36 +461,49 @@ describe('selectApprovals', () => {
440
461
  const account = MultisigConfig.getAddress(config)
441
462
  const hash = MultisigOperation.getHash({
442
463
  account,
443
- configVersion: 1n,
464
+ config: { ...config, version: 1n },
444
465
  transaction,
445
466
  type: 'transaction',
446
467
  })
447
468
  const childHash = MultisigConfig.getSignPayload({
448
469
  account: child,
449
- config: { version: 1n },
470
+ config: { ...childConfig, version: 1n },
450
471
  payload: hash,
451
472
  })
452
473
 
453
- await expect(
454
- MultisigOperation.selectApprovals({
455
- account,
456
- approvals: [
457
- SignatureEnvelope.serialize({
458
- account: child,
459
- config: MultisigConfig.from({ ...childConfig, version: 1n }),
460
- signatures: [
461
- SignatureEnvelope.deserialize(
462
- signApproval(owners[1]!, childHash),
463
- ),
464
- ],
465
- type: 'multisig',
466
- }),
474
+ const selection = await MultisigOperation.selectApprovals({
475
+ account,
476
+ approvals: [
477
+ SignatureEnvelope.serialize({
478
+ account: child,
479
+ config: MultisigConfig.from({ ...childConfig, version: 1n }),
480
+ signatures: [
481
+ SignatureEnvelope.deserialize(signApproval(owners[1]!, childHash)),
482
+ ],
483
+ type: 'multisig',
484
+ }),
485
+ ],
486
+ config,
487
+ hash,
488
+ })
489
+ expect(selection).toMatchInlineSnapshot(
490
+ {
491
+ approvals: [expect.any(String)],
492
+ selectedApprovals: [expect.any(String)],
493
+ },
494
+ `
495
+ {
496
+ "approvals": [
497
+ Any<String>,
467
498
  ],
468
- config,
469
- hash,
470
- }),
471
- ).rejects.toThrowErrorMatchingInlineSnapshot(
472
- `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: nested multisig owner 0x7888d60e9cc26c8569d394fce435c248f1e49c3b requires a config resolver.]`,
499
+ "selectedApprovals": [
500
+ Any<String>,
501
+ ],
502
+ "signatureCount": 1,
503
+ "threshold": 1,
504
+ "weight": 1,
505
+ }
506
+ `,
473
507
  )
474
508
  })
475
509
 
@@ -489,7 +523,7 @@ describe('selectApprovals', () => {
489
523
  const account = MultisigConfig.getAddress(config)
490
524
  const hash = MultisigOperation.getHash({
491
525
  account,
492
- configVersion: 1n,
526
+ config: { ...config, version: 1n },
493
527
  transaction,
494
528
  type: 'transaction',
495
529
  })
@@ -531,7 +565,6 @@ describe('selectApprovals', () => {
531
565
  ],
532
566
  config,
533
567
  hash,
534
- resolveConfig: () => ({ config: childConfig, version: 0n }),
535
568
  })
536
569
  expect({
537
570
  signatureCount: selection.signatureCount,
@@ -553,7 +586,7 @@ describe('selectApprovals', () => {
553
586
  })
554
587
  const hash = MultisigOperation.getHash({
555
588
  account,
556
- configVersion: 2n,
589
+ config: { ...config, version: 2n },
557
590
  transaction,
558
591
  type: 'transaction',
559
592
  })
@@ -595,18 +628,18 @@ describe('selectApprovals', () => {
595
628
  const account = MultisigConfig.getAddress(config)
596
629
  const hash = MultisigOperation.getHash({
597
630
  account,
598
- configVersion: 1n,
631
+ config: { ...config, version: 1n },
599
632
  transaction,
600
633
  type: 'transaction',
601
634
  })
602
635
  const childHash = MultisigConfig.getSignPayload({
603
636
  account: child,
604
- config: { version: 1n },
637
+ config: { ...childConfig, version: 1n },
605
638
  payload: hash,
606
639
  })
607
640
  const grandchildHash = MultisigConfig.getSignPayload({
608
641
  account: grandchild,
609
- config: { version: 1n },
642
+ config: { ...grandchildConfig, version: 1n },
610
643
  payload: childHash,
611
644
  })
612
645
 
@@ -637,20 +670,6 @@ describe('selectApprovals', () => {
637
670
  ],
638
671
  config,
639
672
  hash,
640
- resolveConfig: ({ account }) => {
641
- if (Address.isEqual(account, child))
642
- return {
643
- config: MultisigConfig.from({ ...childConfig, version: 1n }),
644
- version: 1n,
645
- }
646
- return {
647
- config: MultisigConfig.from({
648
- ...grandchildConfig,
649
- version: 1n,
650
- }),
651
- version: 1n,
652
- }
653
- },
654
673
  }),
655
674
  ).rejects.toThrowErrorMatchingInlineSnapshot(
656
675
  `[MultisigOperation.InvalidApprovalError: Invalid multisig approval: nested multisig owner 0xf529c8f6b2b4c72102af4cfe5eeb55b7d45dede2 is invalid.]`,
@@ -658,15 +677,107 @@ describe('selectApprovals', () => {
658
677
  })
659
678
  })
660
679
 
680
+ describe('serializeKeyAuthorization', () => {
681
+ test('behavior: current and initial authorizations', async () => {
682
+ const results = []
683
+ for (const applicableConfig of [currentConfig, config]) {
684
+ const hash = MultisigOperation.getHash({
685
+ account,
686
+ config: applicableConfig,
687
+ keyAuthorization,
688
+ type: 'keyAuthorization',
689
+ })
690
+ const selection = await MultisigOperation.selectApprovals({
691
+ account,
692
+ approvals: [
693
+ signApproval(owners[1]!, hash),
694
+ signApproval(owners[0]!, hash),
695
+ ],
696
+ config: applicableConfig,
697
+ hash,
698
+ })
699
+ const serialized = MultisigOperation.serializeKeyAuthorization(
700
+ keyAuthorization,
701
+ {
702
+ account,
703
+ approvals: selection.selectedApprovals,
704
+ config: applicableConfig,
705
+ },
706
+ )
707
+ const value = KeyAuthorization.deserialize(serialized)
708
+ results.push({
709
+ account:
710
+ value.signature?.type === 'multisig'
711
+ ? value.signature.account
712
+ : undefined,
713
+ hash: Hash.keccak256(serialized),
714
+ signatureCount:
715
+ value.signature?.type === 'multisig'
716
+ ? value.signature.signatures.length
717
+ : 0,
718
+ version:
719
+ value.signature?.type === 'multisig'
720
+ ? value.signature.config.version
721
+ : undefined,
722
+ })
723
+ }
724
+
725
+ expect(results).toMatchInlineSnapshot(`
726
+ [
727
+ {
728
+ "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
729
+ "hash": "0x14b3a60f7c3120e3983b1f6e085ab5b234e71f58f0a4f39d19a5ff64b89a2afe",
730
+ "signatureCount": 2,
731
+ "version": 1n,
732
+ },
733
+ {
734
+ "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
735
+ "hash": "0xbfdc90810a0634f413e627bdefea88ae8c42ed41d6670a70fd1d7574aedda2a4",
736
+ "signatureCount": 2,
737
+ "version": 0n,
738
+ },
739
+ ]
740
+ `)
741
+ })
742
+
743
+ test('error: signed authorization', async () => {
744
+ const selection = await MultisigOperation.selectApprovals({
745
+ account,
746
+ approvals: [
747
+ signApproval(owners[0]!, keyAuthorizationHash),
748
+ signApproval(owners[1]!, keyAuthorizationHash),
749
+ ],
750
+ config: currentConfig,
751
+ hash: keyAuthorizationHash,
752
+ })
753
+ const signed = MultisigOperation.serializeKeyAuthorization(
754
+ keyAuthorization,
755
+ {
756
+ account,
757
+ approvals: selection.selectedApprovals,
758
+ config: currentConfig,
759
+ },
760
+ )
761
+
762
+ expect(() =>
763
+ MultisigOperation.serializeKeyAuthorization(signed, {
764
+ account,
765
+ approvals: selection.selectedApprovals,
766
+ config: currentConfig,
767
+ }),
768
+ ).toThrowErrorMatchingInlineSnapshot(
769
+ `[MultisigOperation.InvalidOperationError: Invalid multisig operation: keyAuthorization must not contain a signature.]`,
770
+ )
771
+ })
772
+ })
773
+
661
774
  describe('serializeTransaction', () => {
662
- test('initialized and bootstrap transactions', async () => {
775
+ test('current and initial transactions', async () => {
663
776
  const results = []
664
- for (const init of [false, true]) {
665
- const configVersion = init ? 0n : 1n
666
- const applicableConfig = init ? config : initializedConfig
777
+ for (const applicableConfig of [currentConfig, config]) {
667
778
  const hash = MultisigOperation.getHash({
668
779
  account,
669
- configVersion,
780
+ config: applicableConfig,
670
781
  transaction,
671
782
  type: 'transaction',
672
783
  })
@@ -683,10 +794,8 @@ describe('serializeTransaction', () => {
683
794
  account,
684
795
  approvals: selection.approvals,
685
796
  config: applicableConfig,
686
- configVersion,
687
797
  createdAt: 1,
688
798
  hash,
689
- init,
690
799
  signatureCount: selection.signatureCount,
691
800
  status: 'pending',
692
801
  threshold: selection.threshold,
@@ -701,7 +810,7 @@ describe('serializeTransaction', () => {
701
810
  const value = TxEnvelopeTempo.deserialize(serialized)
702
811
  results.push({
703
812
  account: value.signature?.account,
704
- configVersion:
813
+ version:
705
814
  value.signature?.type === 'multisig'
706
815
  ? value.signature.config.version
707
816
  : undefined,
@@ -718,17 +827,17 @@ describe('serializeTransaction', () => {
718
827
  [
719
828
  {
720
829
  "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
721
- "configVersion": 1n,
722
830
  "hash": "0x8309740edaf304284186f7bcfe4527745cd4eb48e7441795ebdd970798091f8f",
723
831
  "signatureCount": 2,
724
832
  "type": "0x76",
833
+ "version": 1n,
725
834
  },
726
835
  {
727
836
  "account": "0xf81b7763d3a6876195d780865bd783dbd97dd36e",
728
- "configVersion": 0n,
729
837
  "hash": "0x636af84d8445d87cbcd33039d5a3a2274a5911036b1b7ceb740ac41e2f638611",
730
838
  "signatureCount": 2,
731
839
  "type": "0x76",
840
+ "version": 0n,
732
841
  },
733
842
  ]
734
843
  `)
@@ -756,7 +865,7 @@ describe('serializeTransaction', () => {
756
865
  for (const transaction of transactions) {
757
866
  const hash = MultisigOperation.getHash({
758
867
  account,
759
- configVersion: 1n,
868
+ config: currentConfig,
760
869
  transaction,
761
870
  type: 'transaction',
762
871
  })
@@ -766,18 +875,16 @@ describe('serializeTransaction', () => {
766
875
  signApproval(owners[0]!, hash),
767
876
  signApproval(owners[1]!, hash),
768
877
  ],
769
- config: initializedConfig,
878
+ config: currentConfig,
770
879
  hash,
771
880
  })
772
881
  const serialized = MultisigOperation.serializeTransaction(
773
882
  MultisigOperation.from({
774
883
  account,
775
884
  approvals: selection.approvals,
776
- config: initializedConfig,
777
- configVersion: 1n,
885
+ config: currentConfig,
778
886
  createdAt: 1,
779
887
  hash,
780
- init: false,
781
888
  signatureCount: selection.signatureCount,
782
889
  status: 'pending',
783
890
  threshold: selection.threshold,
@@ -825,7 +932,7 @@ describe('serializeTransaction', () => {
825
932
  test('rejects an approval not retained by the operation', async () => {
826
933
  const hash = MultisigOperation.getHash({
827
934
  account,
828
- configVersion: 1n,
935
+ config: currentConfig,
829
936
  transaction,
830
937
  type: 'transaction',
831
938
  })
@@ -834,17 +941,15 @@ describe('serializeTransaction', () => {
834
941
  const selection = await MultisigOperation.selectApprovals({
835
942
  account,
836
943
  approvals: [approval_1],
837
- config: initializedConfig,
944
+ config: currentConfig,
838
945
  hash,
839
946
  })
840
947
  const operation = MultisigOperation.from({
841
948
  account,
842
949
  approvals: selection.approvals,
843
- config: initializedConfig,
844
- configVersion: 1n,
950
+ config: currentConfig,
845
951
  createdAt: 1,
846
952
  hash,
847
- init: false,
848
953
  signatureCount: selection.signatureCount,
849
954
  status: 'pending',
850
955
  threshold: selection.threshold,
@@ -907,10 +1012,8 @@ describe('from', () => {
907
1012
  "threshold": 2,
908
1013
  "version": 1n,
909
1014
  },
910
- "configVersion": 1n,
911
1015
  "createdAt": 1,
912
1016
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
913
- "init": false,
914
1017
  "signatureCount": 1,
915
1018
  "status": "pending",
916
1019
  "threshold": 2,
@@ -940,11 +1043,9 @@ describe('from', () => {
940
1043
  "threshold": 2,
941
1044
  "version": 1n,
942
1045
  },
943
- "configVersion": 1n,
944
1046
  "createdAt": 1,
945
1047
  "expiresAt": 10,
946
1048
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
947
- "init": false,
948
1049
  "signatureCount": 2,
949
1050
  "status": "submitting",
950
1051
  "submissionId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -975,10 +1076,8 @@ describe('from', () => {
975
1076
  "threshold": 2,
976
1077
  "version": 1n,
977
1078
  },
978
- "configVersion": 1n,
979
1079
  "createdAt": 1,
980
1080
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
981
- "init": false,
982
1081
  "signatureCount": 2,
983
1082
  "status": "success",
984
1083
  "threshold": 2,
@@ -1004,7 +1103,7 @@ describe('from', () => {
1004
1103
  ...transactionPending,
1005
1104
  hash: MultisigConfig.getSignPayload({
1006
1105
  account,
1007
- config: initializedConfig,
1106
+ config: currentConfig,
1008
1107
  payload: TxEnvelopeTempo.getSignPayload(
1009
1108
  TxEnvelopeTempo.deserialize(transaction),
1010
1109
  ),
@@ -1038,10 +1137,8 @@ describe('from', () => {
1038
1137
  "threshold": 2,
1039
1138
  "version": 1n,
1040
1139
  },
1041
- "configVersion": 1n,
1042
1140
  "createdAt": 1,
1043
1141
  "hash": Any<String>,
1044
- "init": false,
1045
1142
  "signatureCount": 1,
1046
1143
  "status": "pending",
1047
1144
  "threshold": 2,
@@ -1067,7 +1164,7 @@ describe('from', () => {
1067
1164
  ...transactionPending,
1068
1165
  hash: MultisigConfig.getSignPayload({
1069
1166
  account,
1070
- config: initializedConfig,
1167
+ config: currentConfig,
1071
1168
  payload: TxEnvelopeTempo.getSignPayload(
1072
1169
  TxEnvelopeTempo.deserialize(transaction),
1073
1170
  ),
@@ -1078,11 +1175,10 @@ describe('from', () => {
1078
1175
  expect(operation.transaction).toBe(transaction)
1079
1176
  })
1080
1177
 
1081
- test('bootstrap transaction', () => {
1178
+ test('initial transaction', () => {
1082
1179
  const operation = MultisigOperation.from({
1083
1180
  ...transactionPending,
1084
1181
  config,
1085
- configVersion: 0n,
1086
1182
  hash: MultisigConfig.getSignPayload({
1087
1183
  account,
1088
1184
  config,
@@ -1090,7 +1186,6 @@ describe('from', () => {
1090
1186
  TxEnvelopeTempo.deserialize(transaction),
1091
1187
  ),
1092
1188
  }),
1093
- init: true,
1094
1189
  })
1095
1190
 
1096
1191
  expect(operation).toMatchInlineSnapshot(
@@ -1119,10 +1214,8 @@ describe('from', () => {
1119
1214
  "threshold": 2,
1120
1215
  "version": 0n,
1121
1216
  },
1122
- "configVersion": 0n,
1123
1217
  "createdAt": 1,
1124
1218
  "hash": Any<String>,
1125
- "init": true,
1126
1219
  "signatureCount": 1,
1127
1220
  "status": "pending",
1128
1221
  "threshold": 2,
@@ -1135,31 +1228,6 @@ describe('from', () => {
1135
1228
  )
1136
1229
  })
1137
1230
 
1138
- test('initialized transaction at config version zero', () => {
1139
- const operation = MultisigOperation.from({
1140
- ...transactionPending,
1141
- config,
1142
- configVersion: 0n,
1143
- hash: MultisigConfig.getSignPayload({
1144
- account,
1145
- config,
1146
- payload: TxEnvelopeTempo.getSignPayload(
1147
- TxEnvelopeTempo.deserialize(transaction),
1148
- ),
1149
- }),
1150
- })
1151
-
1152
- expect({
1153
- configVersion: operation.configVersion,
1154
- init: operation.init,
1155
- }).toMatchInlineSnapshot(`
1156
- {
1157
- "configVersion": 0n,
1158
- "init": false,
1159
- }
1160
- `)
1161
- })
1162
-
1163
1231
  test('key authorization states', () => {
1164
1232
  const pending = MultisigOperation.from(keyAuthorizationPending)
1165
1233
  const authorization = KeyAuthorization.deserialize(keyAuthorization)
@@ -1170,7 +1238,7 @@ describe('from', () => {
1170
1238
  KeyAuthorization.from(authorization, {
1171
1239
  signature: {
1172
1240
  account,
1173
- config: initializedConfig,
1241
+ config: currentConfig,
1174
1242
  signatures: [
1175
1243
  SignatureEnvelope.deserialize(approval_1),
1176
1244
  SignatureEnvelope.deserialize(approval_2),
@@ -1206,10 +1274,8 @@ describe('from', () => {
1206
1274
  "threshold": 2,
1207
1275
  "version": 1n,
1208
1276
  },
1209
- "configVersion": 1n,
1210
1277
  "createdAt": 1,
1211
1278
  "hash": "0xf6995eb69c12c03d3d13b357abf7cac22b4effe52fba8ff02e5aef26161f77a0",
1212
- "init": false,
1213
1279
  "keyAuthorization": "0xf838f782107980943333333333333333333333333333333333333333846b49d2008080808094f81b7763d3a6876195d780865bd783dbd97dd36e",
1214
1280
  "signatureCount": 1,
1215
1281
  "status": "pending",
@@ -1239,10 +1305,8 @@ describe('from', () => {
1239
1305
  "threshold": 2,
1240
1306
  "version": 1n,
1241
1307
  },
1242
- "configVersion": 1n,
1243
1308
  "createdAt": 1,
1244
1309
  "hash": "0xf6995eb69c12c03d3d13b357abf7cac22b4effe52fba8ff02e5aef26161f77a0",
1245
- "init": false,
1246
1310
  "keyAuthorization": "0xf901b3f782107980943333333333333333333333333333333333333333846b49d2008080808094f81b7763d3a6876195d780865bd783dbd97dd36eb9017805f9017494f81b7763d3a6876195d780865bd783dbd97dd36ef852a000000000000000000000000000000000000000000000000000000000000000000102eed69407e1ed8ea0e9601e5546b0a03aed683df360140701d694288f0cd85005f34168f731a468aef268c2f9456f01f90108b88201000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000065ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c8734640c4998ff7e374b06ce1a64a2ecd82ab036384fb83d9a79b127a27d503200b88201000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000047cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc4766997807775510db8ed040293d9ac69f7430dbba7dade63ce982299e04b79d227873d100",
1247
1311
  "signatureCount": 2,
1248
1312
  "status": "success",
@@ -1255,7 +1319,7 @@ describe('from', () => {
1255
1319
  `)
1256
1320
  })
1257
1321
 
1258
- test('bootstrap key authorization', () => {
1322
+ test('initial key authorization', () => {
1259
1323
  const authorization = KeyAuthorization.deserialize(keyAuthorization)
1260
1324
  const keyAuthorization_ = KeyAuthorization.serialize(
1261
1325
  KeyAuthorization.from(authorization, {
@@ -1274,13 +1338,11 @@ describe('from', () => {
1274
1338
  ...keyAuthorizationPending,
1275
1339
  approvals: [approval_1, approval_2],
1276
1340
  config,
1277
- configVersion: 0n,
1278
1341
  hash: MultisigConfig.getSignPayload({
1279
1342
  account,
1280
1343
  config,
1281
1344
  payload: KeyAuthorization.getSignPayload(authorization),
1282
1345
  }),
1283
- init: true,
1284
1346
  keyAuthorization: keyAuthorization_,
1285
1347
  signatureCount: 2,
1286
1348
  status: 'success',
@@ -1314,10 +1376,8 @@ describe('from', () => {
1314
1376
  "threshold": 2,
1315
1377
  "version": 0n,
1316
1378
  },
1317
- "configVersion": 0n,
1318
1379
  "createdAt": 1,
1319
1380
  "hash": Any<String>,
1320
- "init": true,
1321
1381
  "keyAuthorization": Any<String>,
1322
1382
  "signatureCount": 2,
1323
1383
  "status": "success",
@@ -1361,10 +1421,8 @@ describe('RPC conversion', () => {
1361
1421
  "threshold": 2,
1362
1422
  "version": "0x1",
1363
1423
  },
1364
- "configVersion": "0x1",
1365
1424
  "createdAt": 1,
1366
1425
  "hash": "0xf6995eb69c12c03d3d13b357abf7cac22b4effe52fba8ff02e5aef26161f77a0",
1367
- "init": false,
1368
1426
  "keyAuthorization": "0xf838f782107980943333333333333333333333333333333333333333846b49d2008080808094f81b7763d3a6876195d780865bd783dbd97dd36e",
1369
1427
  "signatureCount": 1,
1370
1428
  "status": "pending",
@@ -1393,10 +1451,8 @@ describe('RPC conversion', () => {
1393
1451
  "threshold": 2,
1394
1452
  "version": "0x1",
1395
1453
  },
1396
- "configVersion": "0x1",
1397
1454
  "createdAt": 1,
1398
1455
  "hash": "0xcdbc24a8fb192f799c5d166b13a99fb29cbb15e71a5e730988d6f8b3c5959d02",
1399
- "init": false,
1400
1456
  "signatureCount": 1,
1401
1457
  "status": "pending",
1402
1458
  "threshold": 2,
@@ -1529,7 +1585,7 @@ describe('validation', () => {
1529
1585
  account: '0x0000000000000000000000000000000000000000',
1530
1586
  hash: MultisigConfig.getSignPayload({
1531
1587
  account: '0x0000000000000000000000000000000000000000',
1532
- config: initializedConfig,
1588
+ config: currentConfig,
1533
1589
  payload: TxEnvelopeTempo.getSignPayload(
1534
1590
  TxEnvelopeTempo.deserialize(transaction),
1535
1591
  ),
@@ -1596,7 +1652,7 @@ describe('validation', () => {
1596
1652
  },
1597
1653
  },
1598
1654
  {
1599
- name: 'nested bootstrap owner approval',
1655
+ name: 'nested non-owner approval',
1600
1656
  operation: {
1601
1657
  ...transactionPending,
1602
1658
  approvals: [
@@ -1609,35 +1665,48 @@ describe('validation', () => {
1609
1665
  ],
1610
1666
  },
1611
1667
  },
1612
- {
1613
- name: 'bootstrap with initialized version',
1614
- operation: { ...transactionPending, init: true },
1615
- },
1616
1668
  ])('rejects $name', ({ operation }) => {
1617
1669
  expect(() =>
1618
1670
  MultisigOperation.from(operation as MultisigOperation.Operation),
1619
1671
  ).toThrowError(MultisigOperation.InvalidOperationError)
1620
1672
  })
1621
1673
 
1622
- test('rejects mismatched config versions', () => {
1674
+ test('rejects an initial config for another account', () => {
1675
+ const config = MultisigConfig.from({
1676
+ ...transactionPending.config,
1677
+ salt: `0x${'ff'.repeat(32)}`,
1678
+ version: 0n,
1679
+ })
1623
1680
  expect(() =>
1624
1681
  MultisigOperation.from({
1625
1682
  ...transactionPending,
1626
- config: { ...initializedConfig, version: 2n },
1683
+ config,
1684
+ hash: MultisigConfig.getSignPayload({
1685
+ account,
1686
+ config,
1687
+ payload: TxEnvelopeTempo.getSignPayload(
1688
+ TxEnvelopeTempo.deserialize(transaction),
1689
+ ),
1690
+ }),
1627
1691
  }),
1628
1692
  ).toThrowErrorMatchingInlineSnapshot(
1629
- `[MultisigOperation.InvalidOperationError: Invalid multisig operation: config.version must equal configVersion.]`,
1693
+ `
1694
+ [MultisigOperation.InvalidOperationError: Invalid multisig operation.
1695
+
1696
+ Details: Invalid native multisig owner approval: initial multisig config does not derive account.]
1697
+ `,
1630
1698
  )
1631
1699
  })
1632
1700
 
1633
1701
  test('rejects noncanonical RPC quantities', () => {
1702
+ const operation = MultisigOperation.toRpc(transactionPending)
1634
1703
  expect(() =>
1635
1704
  MultisigOperation.fromRpc({
1636
- ...MultisigOperation.toRpc(transactionPending),
1637
- configVersion: '0x01',
1705
+ ...operation,
1706
+ config: { ...operation.config, version: '0x01' },
1638
1707
  }),
1639
1708
  ).toThrowError(
1640
- 'Invalid multisig operation: configVersion must use canonical quantity encoding.',
1709
+ 'Invalid multisig operation: config.version must use canonical quantity encoding.',
1641
1710
  )
1642
1711
  })
1643
1712
 
@@ -1650,7 +1719,7 @@ describe('validation', () => {
1650
1719
  KeyAuthorization.from(authorization, {
1651
1720
  signature: {
1652
1721
  account,
1653
- config: initializedConfig,
1722
+ config: currentConfig,
1654
1723
  signatures: [
1655
1724
  SignatureEnvelope.deserialize(approval_1),
1656
1725
  SignatureEnvelope.deserialize(approval_3),
@@ -1674,7 +1743,7 @@ describe('validation', () => {
1674
1743
  const signatures = [
1675
1744
  ...SignatureEnvelope.sortMultisigApprovals({
1676
1745
  account,
1677
- config: initializedConfig,
1746
+ config: currentConfig,
1678
1747
  payload: KeyAuthorization.getSignPayload(authorization),
1679
1748
  signatures: [
1680
1749
  SignatureEnvelope.deserialize(approval_1),
@@ -1689,7 +1758,7 @@ describe('validation', () => {
1689
1758
  KeyAuthorization.from(authorization, {
1690
1759
  signature: {
1691
1760
  account,
1692
- config: initializedConfig,
1761
+ config: currentConfig,
1693
1762
  signatures,
1694
1763
  type: 'multisig',
1695
1764
  },
@@ -1714,7 +1783,7 @@ describe('validation', () => {
1714
1783
  KeyAuthorization.from(authorization, {
1715
1784
  signature: {
1716
1785
  account,
1717
- config: initializedConfig,
1786
+ config: currentConfig,
1718
1787
  signatures: [
1719
1788
  SignatureEnvelope.deserialize(approval_1),
1720
1789
  SignatureEnvelope.deserialize(approval_1),
@@ -1763,7 +1832,7 @@ describe('validation', () => {
1763
1832
  })
1764
1833
  const selected = SignatureEnvelope.sortMultisigApprovals({
1765
1834
  account,
1766
- config: initializedConfig,
1835
+ config: currentConfig,
1767
1836
  payload: KeyAuthorization.getSignPayload(authorization),
1768
1837
  signatures: [selectedNested, SignatureEnvelope.deserialize(approval_2)],
1769
1838
  })
@@ -1774,7 +1843,7 @@ describe('validation', () => {
1774
1843
  KeyAuthorization.from(authorization, {
1775
1844
  signature: {
1776
1845
  account,
1777
- config: initializedConfig,
1846
+ config: currentConfig,
1778
1847
  signatures: selected,
1779
1848
  type: 'multisig',
1780
1849
  },
@@ -1790,7 +1859,7 @@ describe('validation', () => {
1790
1859
  )
1791
1860
  })
1792
1861
 
1793
- test('accepts case-insensitive bootstrap configs', () => {
1862
+ test('accepts case-insensitive initial configs', () => {
1794
1863
  const config = MultisigConfig.from({
1795
1864
  owners: [
1796
1865
  {
@@ -1831,14 +1900,12 @@ describe('validation', () => {
1831
1900
  account,
1832
1901
  approvals,
1833
1902
  config,
1834
- configVersion: 0n,
1835
1903
  createdAt: 1,
1836
1904
  hash: MultisigConfig.getSignPayload({
1837
1905
  account,
1838
1906
  config,
1839
1907
  payload: KeyAuthorization.getSignPayload(authorization),
1840
1908
  }),
1841
- init: true,
1842
1909
  keyAuthorization: KeyAuthorization.serialize(
1843
1910
  KeyAuthorization.from(authorization, {
1844
1911
  signature: {