ox 0.14.42 → 0.14.44

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 (74) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_cjs/tempo/MultisigConfig.js +9 -2
  3. package/_cjs/tempo/MultisigConfig.js.map +1 -1
  4. package/_cjs/tempo/MultisigSimulation.js +115 -0
  5. package/_cjs/tempo/MultisigSimulation.js.map +1 -0
  6. package/_cjs/tempo/SignatureEnvelope.js +12 -21
  7. package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
  8. package/_cjs/tempo/TransactionRequest.js +7 -7
  9. package/_cjs/tempo/TransactionRequest.js.map +1 -1
  10. package/_cjs/tempo/index.js +2 -2
  11. package/_cjs/tempo/index.js.map +1 -1
  12. package/_cjs/version.js +1 -1
  13. package/_esm/tempo/MultisigConfig.js +14 -4
  14. package/_esm/tempo/MultisigConfig.js.map +1 -1
  15. package/_esm/tempo/MultisigSimulation.js +145 -0
  16. package/_esm/tempo/MultisigSimulation.js.map +1 -0
  17. package/_esm/tempo/SignatureEnvelope.js +12 -21
  18. package/_esm/tempo/SignatureEnvelope.js.map +1 -1
  19. package/_esm/tempo/TransactionRequest.js +7 -7
  20. package/_esm/tempo/TransactionRequest.js.map +1 -1
  21. package/_esm/tempo/index.js +4 -4
  22. package/_esm/tempo/index.js.map +1 -1
  23. package/_esm/version.js +1 -1
  24. package/_types/tempo/KeyAuthorization.d.ts +1 -1
  25. package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
  26. package/_types/tempo/MultisigConfig.d.ts +5 -3
  27. package/_types/tempo/MultisigConfig.d.ts.map +1 -1
  28. package/_types/tempo/MultisigOperation.d.ts +2 -2
  29. package/_types/tempo/MultisigOperation.d.ts.map +1 -1
  30. package/_types/tempo/MultisigSimulation.d.ts +132 -0
  31. package/_types/tempo/MultisigSimulation.d.ts.map +1 -0
  32. package/_types/tempo/SignatureEnvelope.d.ts +10 -34
  33. package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
  34. package/_types/tempo/TransactionRequest.d.ts +9 -9
  35. package/_types/tempo/TransactionRequest.d.ts.map +1 -1
  36. package/_types/tempo/index.d.ts +4 -4
  37. package/_types/tempo/index.d.ts.map +1 -1
  38. package/_types/version.d.ts +1 -1
  39. package/package.json +9 -9
  40. package/tempo/AuthorizationTempo.test.ts +4 -0
  41. package/tempo/KeyAuthorization.test-d.ts +1 -12
  42. package/tempo/KeyAuthorization.test.ts +37 -9
  43. package/tempo/KeyAuthorization.ts +3 -3
  44. package/tempo/MultisigConfig.test.ts +21 -5
  45. package/tempo/MultisigConfig.ts +18 -6
  46. package/tempo/MultisigOperation.test.ts +37 -37
  47. package/tempo/MultisigOperation.ts +2 -2
  48. package/tempo/MultisigSimulation/package.json +6 -0
  49. package/tempo/MultisigSimulation.test-d/package.json +6 -0
  50. package/tempo/MultisigSimulation.test-d.ts +33 -0
  51. package/tempo/MultisigSimulation.test.ts +284 -0
  52. package/tempo/MultisigSimulation.ts +266 -0
  53. package/tempo/RpcSchemaTempo.test-d.ts +4 -4
  54. package/tempo/SignatureEnvelope.test-d.ts +8 -44
  55. package/tempo/SignatureEnvelope.test.ts +106 -65
  56. package/tempo/SignatureEnvelope.ts +27 -61
  57. package/tempo/Transaction.test.ts +61 -0
  58. package/tempo/TransactionRequest.test-d.ts +9 -9
  59. package/tempo/TransactionRequest.test.ts +122 -49
  60. package/tempo/TransactionRequest.ts +20 -16
  61. package/tempo/index.ts +4 -4
  62. package/tempo/multisig.e2e.test.ts +71 -21
  63. package/version.ts +1 -1
  64. package/_cjs/tempo/MultisigWitness.js +0 -92
  65. package/_cjs/tempo/MultisigWitness.js.map +0 -1
  66. package/_esm/tempo/MultisigWitness.js +0 -123
  67. package/_esm/tempo/MultisigWitness.js.map +0 -1
  68. package/_types/tempo/MultisigWitness.d.ts +0 -106
  69. package/_types/tempo/MultisigWitness.d.ts.map +0 -1
  70. package/tempo/MultisigWitness/package.json +0 -6
  71. package/tempo/MultisigWitness.test-d/package.json +0 -6
  72. package/tempo/MultisigWitness.test-d.ts +0 -42
  73. package/tempo/MultisigWitness.test.ts +0 -289
  74. package/tempo/MultisigWitness.ts +0 -210
@@ -68,6 +68,9 @@ const signature_keychain_webauthn = SignatureEnvelope.from({
68
68
  version: 'v2',
69
69
  })
70
70
 
71
+ const signature_multisig_rpc =
72
+ '0xf89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b' as const
73
+
71
74
  describe('assert', () => {
72
75
  describe('secp256k1', () => {
73
76
  test('behavior: validates valid signature', () => {
@@ -1131,7 +1134,7 @@ describe('from', () => {
1131
1134
  },
1132
1135
  `
1133
1136
  {
1134
- "account": "0x8820d1497eeaf4f68e00b2cfc00a2f3b1dbb00da",
1137
+ "account": "0xf4b916c5aea0fb199bd942389be00db0690c961f",
1135
1138
  "config": {
1136
1139
  "owners": [
1137
1140
  {
@@ -2468,6 +2471,72 @@ describe('fromRpc', () => {
2468
2471
  expect(envelope.keyId).toBe('0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c')
2469
2472
  })
2470
2473
  })
2474
+
2475
+ describe('multisig', () => {
2476
+ test('behavior: converts an untagged serialized multisig signature', () => {
2477
+ expect(
2478
+ SignatureEnvelope.fromRpc(signature_multisig_rpc),
2479
+ ).toMatchInlineSnapshot(`
2480
+ {
2481
+ "account": "0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b",
2482
+ "config": {
2483
+ "owners": [
2484
+ {
2485
+ "owner": "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
2486
+ "weight": 1,
2487
+ },
2488
+ ],
2489
+ "salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
2490
+ "threshold": 1,
2491
+ "version": 0n,
2492
+ },
2493
+ "signatures": [
2494
+ {
2495
+ "signature": {
2496
+ "r": 60871800714128149016591846789173983752390955456021923556141688418770269698437n,
2497
+ "s": 24367763726302312398084372528434045669788111037623467391175388828437596076276n,
2498
+ "yParity": 0,
2499
+ },
2500
+ "type": "secp256k1",
2501
+ },
2502
+ ],
2503
+ "type": "multisig",
2504
+ }
2505
+ `)
2506
+ })
2507
+
2508
+ test('error: rejects a payload with the transaction type byte', () => {
2509
+ expect(() =>
2510
+ SignatureEnvelope.fromRpc(`0x05${signature_multisig_rpc.slice(2)}`),
2511
+ ).toThrowErrorMatchingInlineSnapshot(`
2512
+ [SignatureEnvelope.InvalidSerializedError: Unable to deserialize signature envelope: invalid multisig wire shape: expected exactly three fields
2513
+
2514
+ Serialized: 0x0505f89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b]
2515
+ `)
2516
+ })
2517
+
2518
+ test('error: rejects trailing bytes', () => {
2519
+ expect(() =>
2520
+ SignatureEnvelope.fromRpc(`${signature_multisig_rpc}00`),
2521
+ ).toThrowErrorMatchingInlineSnapshot(`
2522
+ [SignatureEnvelope.InvalidSerializedError: Unable to deserialize signature envelope: invalid multisig RPC signature
2523
+
2524
+ Serialized: 0xf89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b00]
2525
+ `)
2526
+ })
2527
+
2528
+ test('error: rejects a structured multisig signature', () => {
2529
+ expect(() =>
2530
+ SignatureEnvelope.fromRpc({
2531
+ account: '0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b',
2532
+ config: {},
2533
+ signatures: [],
2534
+ } as never),
2535
+ ).toThrowErrorMatchingInlineSnapshot(
2536
+ `[SignatureEnvelope.CoercionError: Unable to coerce value (\`{"account":"0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b","config":{},"signatures":[]}\`) to a valid signature envelope.]`,
2537
+ )
2538
+ })
2539
+ })
2471
2540
  })
2472
2541
 
2473
2542
  describe('toRpc', () => {
@@ -2565,6 +2634,7 @@ describe('toRpc', () => {
2565
2634
  const rpc = SignatureEnvelope.toRpc(
2566
2635
  signature_keychain_p256,
2567
2636
  ) as SignatureEnvelope.KeychainRpc
2637
+ if (typeof rpc.signature === 'string') throw new Error('unreachable')
2568
2638
 
2569
2639
  expect(rpc.type).toBe('keychain')
2570
2640
  expect(rpc.userAddress).toBe(signature_keychain_p256.userAddress)
@@ -2577,6 +2647,7 @@ describe('toRpc', () => {
2577
2647
  const rpc = SignatureEnvelope.toRpc(
2578
2648
  signature_keychain_webauthn,
2579
2649
  ) as SignatureEnvelope.KeychainRpc
2650
+ if (typeof rpc.signature === 'string') throw new Error('unreachable')
2580
2651
 
2581
2652
  expect(rpc.type).toBe('keychain')
2582
2653
  expect(rpc.userAddress).toBe(signature_keychain_webauthn.userAddress)
@@ -2620,6 +2691,18 @@ describe('toRpc', () => {
2620
2691
  expect(rpc.keyId).toBeUndefined()
2621
2692
  })
2622
2693
  })
2694
+
2695
+ describe('multisig', () => {
2696
+ test('behavior: removes the transaction type byte', () => {
2697
+ const envelope = SignatureEnvelope.deserialize(
2698
+ `0x05${signature_multisig_rpc.slice(2)}`,
2699
+ )
2700
+
2701
+ expect(SignatureEnvelope.toRpc(envelope)).toMatchInlineSnapshot(
2702
+ `"${signature_multisig_rpc}"`,
2703
+ )
2704
+ })
2705
+ })
2623
2706
  })
2624
2707
 
2625
2708
  describe('roundtrip: toRpc <-> fromRpc', () => {
@@ -2854,18 +2937,18 @@ describe('CoercionError', () => {
2854
2937
 
2855
2938
  describe('multisig', () => {
2856
2939
  const initial =
2857
- '0x05f897949dba7f426b711d4893c11611eacf7cc334e7146bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b' as const
2940
+ '0x05f89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b' as const
2858
2941
  const current =
2859
- '0x05f897949dba7f426b711d4893c11611eacf7cc334e7146bf83ba000000000000000000000000000000000000000000000000000000000000000000101d7d6942b5ad5c4795c026514f8317c7a215e218dccd6cf01f843b8414a0e5b5b4a90f08e6e8d676a73a22dc2cf022ffdcc9299512b5d9a6daf66e0504a395a2ef6f6c0f173910b875c45d01aa66d928e56ba6f49bbc8186f80268bf51b' as const
2942
+ '0x05f89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000000101d7d6942b5ad5c4795c026514f8317c7a215e218dccd6cf01f843b8414a0e5b5b4a90f08e6e8d676a73a22dc2cf022ffdcc9299512b5d9a6daf66e0504a395a2ef6f6c0f173910b875c45d01aa66d928e56ba6f49bbc8186f80268bf51b' as const
2860
2943
  const nested =
2861
- '0x05f8f0949969e2243075b27a8eab61009c59b77ab13b83f6f83ba033333333333333333333333333333333333333333333333333333333333333338001d7d6944f9f5b162a7464bcc260ce44d7ae0d935f9c583701f89cb89a05f897944f9f5b162a7464bcc260ce44d7ae0d935f9c5837f83ba022222222222222222222222222222222222222222222222222222222222222228001d7d6946813eb9362372eef6200f3b1dbc3f819671cba6901f843b841032aa6f3ea7b0b7069720d0f3891983c493d149326c5c957d864ed7371b8475e3e95325079b24491f4b6d68920e4b3bacd7c6094df6ed88b8674864ab559c8fb1b' as const
2944
+ '0x05f8f0945f0287385ec182f906c238bec5f87692d48b23f2f83ba033333333333333333333333333333333333333333333333333333333333333338001d7d69470845f2897b639686cb383799d605c52315d785501f89cb89a05f8979470845f2897b639686cb383799d605c52315d7855f83ba022222222222222222222222222222222222222222222222222222222222222228001d7d6946813eb9362372eef6200f3b1dbc3f819671cba6901f843b841032aa6f3ea7b0b7069720d0f3891983c493d149326c5c957d864ed7371b8475e3e95325079b24491f4b6d68920e4b3bacd7c6094df6ed88b8674864ab559c8fb1b' as const
2862
2945
 
2863
- test('example: decodes and re-encodes the frozen initial witness', () => {
2946
+ test('example: decodes and re-encodes the frozen initial signature', () => {
2864
2947
  const envelope = SignatureEnvelope.deserialize(initial)
2865
2948
 
2866
2949
  expect(envelope).toMatchInlineSnapshot(`
2867
2950
  {
2868
- "account": "0x9dba7f426b711d4893c11611eacf7cc334e7146b",
2951
+ "account": "0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b",
2869
2952
  "config": {
2870
2953
  "owners": [
2871
2954
  {
@@ -2893,12 +2976,12 @@ describe('multisig', () => {
2893
2976
  expect(SignatureEnvelope.serialize(envelope)).toBe(initial)
2894
2977
  })
2895
2978
 
2896
- test('example: decodes and re-encodes the frozen current witness', () => {
2979
+ test('example: decodes and re-encodes the frozen current signature', () => {
2897
2980
  const envelope = SignatureEnvelope.deserialize(current)
2898
2981
 
2899
2982
  expect(envelope).toMatchInlineSnapshot(`
2900
2983
  {
2901
- "account": "0x9dba7f426b711d4893c11611eacf7cc334e7146b",
2984
+ "account": "0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b",
2902
2985
  "config": {
2903
2986
  "owners": [
2904
2987
  {
@@ -2926,16 +3009,16 @@ describe('multisig', () => {
2926
3009
  expect(SignatureEnvelope.serialize(envelope)).toBe(current)
2927
3010
  })
2928
3011
 
2929
- test('example: decodes and re-encodes the frozen nested witness', () => {
3012
+ test('example: decodes and re-encodes the frozen nested signature', () => {
2930
3013
  const envelope = SignatureEnvelope.deserialize(nested)
2931
3014
 
2932
3015
  expect(envelope).toMatchInlineSnapshot(`
2933
3016
  {
2934
- "account": "0x9969e2243075b27a8eab61009c59b77ab13b83f6",
3017
+ "account": "0x5f0287385ec182f906c238bec5f87692d48b23f2",
2935
3018
  "config": {
2936
3019
  "owners": [
2937
3020
  {
2938
- "owner": "0x4f9f5b162a7464bcc260ce44d7ae0d935f9c5837",
3021
+ "owner": "0x70845f2897b639686cb383799d605c52315d7855",
2939
3022
  "weight": 1,
2940
3023
  },
2941
3024
  ],
@@ -2945,7 +3028,7 @@ describe('multisig', () => {
2945
3028
  },
2946
3029
  "signatures": [
2947
3030
  {
2948
- "account": "0x4f9f5b162a7464bcc260ce44d7ae0d935f9c5837",
3031
+ "account": "0x70845f2897b639686cb383799d605c52315d7855",
2949
3032
  "config": {
2950
3033
  "owners": [
2951
3034
  {
@@ -2995,7 +3078,7 @@ describe('multisig', () => {
2995
3078
 
2996
3079
  expect(decoded).toMatchInlineSnapshot(`
2997
3080
  [
2998
- "0x9dba7f426b711d4893c11611eacf7cc334e7146b",
3081
+ "0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b",
2999
3082
  [
3000
3083
  "0x0000000000000000000000000000000000000000000000000000000000000000",
3001
3084
  "0x",
@@ -3014,7 +3097,7 @@ describe('multisig', () => {
3014
3097
  `)
3015
3098
  })
3016
3099
 
3017
- test('behavior: round trips initial and current RPC witnesses', () => {
3100
+ test('behavior: round trips initial and current RPC signatures', () => {
3018
3101
  const initialEnvelope = SignatureEnvelope.deserialize(initial)
3019
3102
  const currentEnvelope = SignatureEnvelope.deserialize(current)
3020
3103
  const rpc = {
@@ -3024,50 +3107,8 @@ describe('multisig', () => {
3024
3107
 
3025
3108
  expect(rpc).toMatchInlineSnapshot(`
3026
3109
  {
3027
- "current": {
3028
- "account": "0x9dba7f426b711d4893c11611eacf7cc334e7146b",
3029
- "config": {
3030
- "owners": [
3031
- {
3032
- "owner": "0x2b5ad5c4795c026514f8317c7a215e218dccd6cf",
3033
- "weight": 1,
3034
- },
3035
- ],
3036
- "salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
3037
- "threshold": 1,
3038
- "version": 1,
3039
- },
3040
- "signatures": [
3041
- {
3042
- "r": "0x4a0e5b5b4a90f08e6e8d676a73a22dc2cf022ffdcc9299512b5d9a6daf66e050",
3043
- "s": "0x4a395a2ef6f6c0f173910b875c45d01aa66d928e56ba6f49bbc8186f80268bf5",
3044
- "type": "secp256k1",
3045
- "yParity": "0x0",
3046
- },
3047
- ],
3048
- },
3049
- "initial": {
3050
- "account": "0x9dba7f426b711d4893c11611eacf7cc334e7146b",
3051
- "config": {
3052
- "owners": [
3053
- {
3054
- "owner": "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
3055
- "weight": 1,
3056
- },
3057
- ],
3058
- "salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
3059
- "threshold": 1,
3060
- "version": 0,
3061
- },
3062
- "signatures": [
3063
- {
3064
- "r": "0x869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f985",
3065
- "s": "0x35dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f4",
3066
- "type": "secp256k1",
3067
- "yParity": "0x0",
3068
- },
3069
- ],
3070
- },
3110
+ "current": "0xf89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000000101d7d6942b5ad5c4795c026514f8317c7a215e218dccd6cf01f843b8414a0e5b5b4a90f08e6e8d676a73a22dc2cf022ffdcc9299512b5d9a6daf66e0504a395a2ef6f6c0f173910b875c45d01aa66d928e56ba6f49bbc8186f80268bf51b",
3111
+ "initial": "0xf89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b",
3071
3112
  }
3072
3113
  `)
3073
3114
  expect(SignatureEnvelope.fromRpc(rpc.initial)).toStrictEqual(
@@ -3078,7 +3119,7 @@ describe('multisig', () => {
3078
3119
  )
3079
3120
  })
3080
3121
 
3081
- test('behavior: derives the account only for an initial witness', () => {
3122
+ test('behavior: derives the account only for an initial config', () => {
3082
3123
  const initialEnvelope = SignatureEnvelope.deserialize(initial)
3083
3124
  if (initialEnvelope.type !== 'multisig') throw new Error('unreachable')
3084
3125
  if (initialEnvelope.config.version !== 0n) throw new Error('unreachable')
@@ -3142,14 +3183,14 @@ describe('multisig', () => {
3142
3183
  signatureCount: envelope.signatures.length,
3143
3184
  }).toMatchInlineSnapshot(`
3144
3185
  {
3145
- "hash": "0x1cb47fcf31fb1ebb3177ec1744eeda195e4d789920d1214af32baaa6150ad5e2",
3186
+ "hash": "0x507fa2d2bc6cf5e7753d4d7cb92fe3d199f64c6eaa9a0bd1d14bfb366028a379",
3146
3187
  "length": 787,
3147
3188
  "signatureCount": 8,
3148
3189
  }
3149
3190
  `)
3150
3191
  })
3151
3192
 
3152
- test('behavior: accepts initial and current nested witnesses', () => {
3193
+ test('behavior: accepts initial and current nested signatures', () => {
3153
3194
  const initialEnvelope = SignatureEnvelope.deserialize(initial)
3154
3195
  const currentEnvelope = SignatureEnvelope.deserialize(current)
3155
3196
  if (
@@ -3191,7 +3232,7 @@ describe('multisig', () => {
3191
3232
  )
3192
3233
  })
3193
3234
 
3194
- test('error: rejects a self-owned current witness', () => {
3235
+ test('error: rejects a self-owned current signature', () => {
3195
3236
  const envelope = SignatureEnvelope.deserialize(current)
3196
3237
  if (envelope.type !== 'multisig') throw new Error('unreachable')
3197
3238
  const account = envelope.config.owners[0]!.owner
@@ -3282,14 +3323,14 @@ describe('multisig', () => {
3282
3323
  {
3283
3324
  name: 'two fields',
3284
3325
  value: Rlp.fromHex([
3285
- '0x9dba7f426b711d4893c11611eacf7cc334e7146b',
3326
+ '0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b',
3286
3327
  [Hex.slice(initial, -65)],
3287
3328
  ]),
3288
3329
  },
3289
3330
  {
3290
3331
  name: 'trailing field',
3291
3332
  value: Rlp.fromHex([
3292
- '0x9dba7f426b711d4893c11611eacf7cc334e7146b',
3333
+ '0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b',
3293
3334
  MultisigConfig.toTuple(
3294
3335
  MultisigConfig.from({
3295
3336
  owners: [
@@ -3370,7 +3411,7 @@ describe('multisig', () => {
3370
3411
  const malformed = Hex.concat(
3371
3412
  '0x05',
3372
3413
  Rlp.fromHex([
3373
- '0x9dba7f426b711d4893c11611eacf7cc334e7146b',
3414
+ '0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b',
3374
3415
  value as never,
3375
3416
  [Hex.slice(initial, -65)],
3376
3417
  ]),
@@ -53,8 +53,6 @@ type SignatureEnvelopeKey =
53
53
  | 'version'
54
54
 
55
55
  type SignatureEnvelopeRpcKey =
56
- | 'account'
57
- | 'config'
58
56
  | 'keyId'
59
57
  | 'metadata'
60
58
  | 'preHash'
@@ -63,7 +61,6 @@ type SignatureEnvelopeRpcKey =
63
61
  | 'r'
64
62
  | 's'
65
63
  | 'signature'
66
- | 'signatures'
67
64
  | 'type'
68
65
  | 'userAddress'
69
66
  | 'v'
@@ -161,7 +158,7 @@ export type SignatureEnvelopeRpc =
161
158
  Secp256k1Rpc | P256Rpc | WebAuthnRpc | KeychainRpc,
162
159
  SignatureEnvelopeRpcKey
163
160
  >
164
- | MultisigRpcOneOf
161
+ | MultisigRpc
165
162
 
166
163
  /** Primitive signature envelope accepted by protocol sidecars. */
167
164
  export type Primitive<bigintType = bigint, numberType = number> = OneOf<
@@ -215,7 +212,7 @@ export type KeychainRpc = {
215
212
  export interface Multisig<bigintType = bigint, numberType = number> {
216
213
  /** Native multisig account address. */
217
214
  account: Address.Address
218
- /** Complete applicable multisig configuration witness. */
215
+ /** Complete applicable multisig configuration. */
219
216
  config: MultisigConfig.Config<bigintType, numberType>
220
217
  /**
221
218
  * Owner approvals over the multisig owner approval digest. Each approval is
@@ -240,33 +237,8 @@ type MultisigOneOf<bigintType = bigint, numberType = number> = Multisig<
240
237
  version?: undefined
241
238
  }
242
239
 
243
- /** RPC-formatted native multisig signature. */
244
- export type MultisigRpc = {
245
- /** Native multisig account address. */
246
- account: Address.Address
247
- /** Complete applicable multisig configuration witness. */
248
- config: MultisigConfig.Config<number>
249
- /** Structured owner approvals. */
250
- signatures: readonly SignatureEnvelopeRpc[]
251
- /** Multisig RPC signatures are untagged. */
252
- type?: undefined
253
- }
254
-
255
- type MultisigRpcOneOf = MultisigRpc & {
256
- keyId?: undefined
257
- metadata?: undefined
258
- preHash?: undefined
259
- pubKeyX?: undefined
260
- pubKeyY?: undefined
261
- r?: undefined
262
- s?: undefined
263
- signature?: undefined
264
- userAddress?: undefined
265
- v?: undefined
266
- version?: undefined
267
- webauthnData?: undefined
268
- yParity?: undefined
269
- }
240
+ /** Canonical RLP-encoded native multisig signature without the `0x05` type byte. */
241
+ export type MultisigRpc = Hex.Hex
270
242
 
271
243
  export type P256<bigintType = bigint, numberType = number> = {
272
244
  prehash: boolean
@@ -1081,7 +1053,7 @@ export declare namespace from {
1081
1053
  | {
1082
1054
  /** Initial native multisig account, derived from config when omitted. */
1083
1055
  account?: Address.Address | undefined
1084
- /** Initial version-0 multisig configuration witness. */
1056
+ /** Initial version-0 multisig configuration. */
1085
1057
  config: MultisigConfig.Input<0 | 0n>
1086
1058
  /** Primitive or nested owner approvals. */
1087
1059
  signatures: readonly SignatureEnvelope[]
@@ -1090,7 +1062,7 @@ export declare namespace from {
1090
1062
  | {
1091
1063
  /** Native multisig account. */
1092
1064
  account: Address.Address
1093
- /** Complete applicable multisig configuration witness. */
1065
+ /** Complete applicable multisig configuration. */
1094
1066
  config: MultisigConfig.Input
1095
1067
  /** Primitive or nested owner approvals. */
1096
1068
  signatures: readonly SignatureEnvelope[]
@@ -1140,6 +1112,20 @@ export declare namespace from {
1140
1112
  * @returns The signature envelope with bigint values.
1141
1113
  */
1142
1114
  export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
1115
+ if (typeof envelope === 'string') {
1116
+ const serialized = Hex.concat(serializedMultisigType, envelope)
1117
+ const result = deserialize(serialized)
1118
+ if (
1119
+ result.type !== 'multisig' ||
1120
+ !Hex.isEqual(serialize(result), serialized)
1121
+ )
1122
+ throw new InvalidSerializedError({
1123
+ reason: 'invalid multisig RPC signature',
1124
+ serialized: envelope,
1125
+ })
1126
+ return result
1127
+ }
1128
+
1143
1129
  if (envelope.type === 'secp256k1')
1144
1130
  return {
1145
1131
  signature: Signature.fromRpc(envelope),
@@ -1222,21 +1208,6 @@ export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
1222
1208
  }
1223
1209
  }
1224
1210
 
1225
- if (
1226
- (envelope as { type?: string | undefined }).type === 'multisig' ||
1227
- ('config' in envelope && 'signatures' in envelope)
1228
- ) {
1229
- const multisig = envelope as MultisigRpc
1230
- const result = {
1231
- account: multisig.account,
1232
- config: MultisigConfig.from(multisig.config),
1233
- signatures: multisig.signatures.map((signature) => fromRpc(signature)),
1234
- type: 'multisig',
1235
- } satisfies Multisig
1236
- assert(result)
1237
- return result
1238
- }
1239
-
1240
1211
  throw new CoercionError({ envelope })
1241
1212
  }
1242
1213
 
@@ -1244,8 +1215,10 @@ export declare namespace fromRpc {
1244
1215
  type ErrorType =
1245
1216
  | assert.ErrorType
1246
1217
  | CoercionError
1218
+ | Hex.concat.ErrorType
1219
+ | Hex.isEqual.ErrorType
1247
1220
  | InvalidSerializedError
1248
- | MultisigConfig.assert.ErrorType
1221
+ | serialize.ErrorType
1249
1222
  | Signature.fromRpc.ErrorType
1250
1223
  | Errors.GlobalErrorType
1251
1224
  }
@@ -1526,7 +1499,7 @@ export declare namespace sortMultisigApprovals {
1526
1499
  type Value = {
1527
1500
  /** The native multisig account address. */
1528
1501
  account: Address.Address
1529
- /** Complete applicable multisig configuration witness. */
1502
+ /** Complete applicable multisig configuration. */
1530
1503
  config: MultisigConfig.Input
1531
1504
  /** The inner transaction sign payload (`tx.signature_hash()`). */
1532
1505
  payload: Hex.Hex | Bytes.Bytes
@@ -1611,15 +1584,7 @@ export function toRpc<const envelope extends toRpc.Input>(
1611
1584
 
1612
1585
  if (type === 'multisig') {
1613
1586
  const multisig = envelope as Multisig
1614
- assert(multisig)
1615
- return {
1616
- account: multisig.account,
1617
- config: {
1618
- ...multisig.config,
1619
- version: Hex.toNumber(Hex.fromNumber(multisig.config.version)),
1620
- },
1621
- signatures: multisig.signatures.map((signature) => toRpc(signature)),
1622
- } as never
1587
+ return Hex.slice(serialize(multisig), 1) as never
1623
1588
  }
1624
1589
 
1625
1590
  throw new CoercionError({ envelope })
@@ -1647,7 +1612,8 @@ export declare namespace toRpc {
1647
1612
  | assert.ErrorType
1648
1613
  | CoercionError
1649
1614
  | Hex.fromNumber.ErrorType
1650
- | Hex.toNumber.ErrorType
1615
+ | Hex.slice.ErrorType
1616
+ | serialize.ErrorType
1651
1617
  | Signature.toRpc.ErrorType
1652
1618
  | Errors.GlobalErrorType
1653
1619
  }
@@ -1,6 +1,9 @@
1
1
  import { Transaction } from 'ox/tempo'
2
2
  import { describe, expect, test } from 'vitest'
3
3
 
4
+ const multisigRpcSignature =
5
+ '0xf89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b' as const
6
+
4
7
  describe('fromRpc', () => {
5
8
  test('default', () => {
6
9
  const transaction = Transaction.fromRpc({
@@ -527,3 +530,61 @@ describe('toRpc', () => {
527
530
  `)
528
531
  })
529
532
  })
533
+
534
+ describe('roundtrip', () => {
535
+ test('behavior: multisig RPC signature', () => {
536
+ const rpc = {
537
+ accessList: [],
538
+ blockHash:
539
+ '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b',
540
+ blockNumber: '0x12f296f',
541
+ calls: [],
542
+ chainId: '0x1',
543
+ feeToken: '0x20c0000000000000000000000000000000000000',
544
+ from: '0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b',
545
+ gas: '0x43f5d',
546
+ hash: '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
547
+ maxFeePerGas: '0x2',
548
+ maxPriorityFeePerGas: '0x1',
549
+ nonce: '0x357',
550
+ signature: multisigRpcSignature,
551
+ transactionIndex: '0x2',
552
+ type: '0x76',
553
+ } as const satisfies Transaction.TempoRpc
554
+ const transaction = Transaction.fromRpc(rpc)
555
+
556
+ expect({
557
+ rpc: Transaction.toRpc(transaction).signature,
558
+ signature: transaction.signature,
559
+ }).toMatchInlineSnapshot(`
560
+ {
561
+ "rpc": "0xf89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b",
562
+ "signature": {
563
+ "account": "0xc4a590afa7337e5cd5eb3aa60cacf91c5400044b",
564
+ "config": {
565
+ "owners": [
566
+ {
567
+ "owner": "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
568
+ "weight": 1,
569
+ },
570
+ ],
571
+ "salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
572
+ "threshold": 1,
573
+ "version": 0n,
574
+ },
575
+ "signatures": [
576
+ {
577
+ "signature": {
578
+ "r": 60871800714128149016591846789173983752390955456021923556141688418770269698437n,
579
+ "s": 24367763726302312398084372528434045669788111037623467391175388828437596076276n,
580
+ "yParity": 0,
581
+ },
582
+ "type": "secp256k1",
583
+ },
584
+ ],
585
+ "type": "multisig",
586
+ },
587
+ }
588
+ `)
589
+ })
590
+ })
@@ -1,24 +1,24 @@
1
1
  import { expectTypeOf, test } from 'vitest'
2
- import type * as MultisigWitness from './MultisigWitness.js'
2
+ import type * as MultisigSimulation from './MultisigSimulation.js'
3
3
  import type * as TransactionRequest from './TransactionRequest.js'
4
4
 
5
5
  declare const request: TransactionRequest.TransactionRequest
6
6
  declare const rpc: TransactionRequest.Rpc
7
7
 
8
- test('transaction requests use domain multisig witnesses', () => {
9
- expectTypeOf(request.multisigWitness?.config.version).toEqualTypeOf<
8
+ test('transaction requests use domain multisig simulation specs', () => {
9
+ expectTypeOf(request.multisigSimulation?.config.version).toEqualTypeOf<
10
10
  bigint | undefined
11
11
  >()
12
12
 
13
- const approval = request.multisigWitness?.approvals[0]
13
+ const approval = request.multisigSimulation?.approvals[0]
14
14
  if (approval?.type === 'multisig')
15
- expectTypeOf(approval.witness.approvals[0]?.keyType).toEqualTypeOf<
16
- MultisigWitness.NestedPrimitiveApproval['keyType']
15
+ expectTypeOf(approval.spec.approvals[0]?.keyType).toEqualTypeOf<
16
+ MultisigSimulation.NestedPrimitiveApproval['keyType']
17
17
  >()
18
18
  })
19
19
 
20
- test('RPC requests use numeric multisig config versions', () => {
21
- expectTypeOf(rpc.multisigWitness?.config.version).toEqualTypeOf<
22
- number | undefined
20
+ test('RPC requests use encoded multisig configurations', () => {
21
+ expectTypeOf(rpc.multisigSimulation?.config).toEqualTypeOf<
22
+ `0x${string}` | undefined
23
23
  >()
24
24
  })