ox 0.14.30 → 0.14.32

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 (67) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/_cjs/core/AbiParameters.js +2 -1
  3. package/_cjs/core/AbiParameters.js.map +1 -1
  4. package/_cjs/core/internal/abiParameters.js +10 -2
  5. package/_cjs/core/internal/abiParameters.js.map +1 -1
  6. package/_cjs/tempo/EarnShares.js +66 -0
  7. package/_cjs/tempo/EarnShares.js.map +1 -0
  8. package/_cjs/tempo/KeyAuthorization.js +39 -10
  9. package/_cjs/tempo/KeyAuthorization.js.map +1 -1
  10. package/_cjs/tempo/MultisigConfig.js +12 -2
  11. package/_cjs/tempo/MultisigConfig.js.map +1 -1
  12. package/_cjs/tempo/SignatureEnvelope.js +167 -46
  13. package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
  14. package/_cjs/tempo/index.js +2 -1
  15. package/_cjs/tempo/index.js.map +1 -1
  16. package/_cjs/version.js +1 -1
  17. package/_esm/core/AbiParameters.js +4 -1
  18. package/_esm/core/AbiParameters.js.map +1 -1
  19. package/_esm/core/internal/abiParameters.js +17 -2
  20. package/_esm/core/internal/abiParameters.js.map +1 -1
  21. package/_esm/tempo/EarnShares.js +167 -0
  22. package/_esm/tempo/EarnShares.js.map +1 -0
  23. package/_esm/tempo/KeyAuthorization.js +41 -9
  24. package/_esm/tempo/KeyAuthorization.js.map +1 -1
  25. package/_esm/tempo/MultisigConfig.js +16 -4
  26. package/_esm/tempo/MultisigConfig.js.map +1 -1
  27. package/_esm/tempo/SignatureEnvelope.js +172 -55
  28. package/_esm/tempo/SignatureEnvelope.js.map +1 -1
  29. package/_esm/tempo/index.js +22 -0
  30. package/_esm/tempo/index.js.map +1 -1
  31. package/_esm/version.js +1 -1
  32. package/_types/core/AbiParameters.d.ts.map +1 -1
  33. package/_types/core/internal/abiParameters.d.ts.map +1 -1
  34. package/_types/core/internal/rpcSchemas/eth.d.ts +16 -0
  35. package/_types/core/internal/rpcSchemas/eth.d.ts.map +1 -1
  36. package/_types/tempo/EarnShares.d.ts +176 -0
  37. package/_types/tempo/EarnShares.d.ts.map +1 -0
  38. package/_types/tempo/KeyAuthorization.d.ts +22 -16
  39. package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
  40. package/_types/tempo/MultisigConfig.d.ts +8 -4
  41. package/_types/tempo/MultisigConfig.d.ts.map +1 -1
  42. package/_types/tempo/SignatureEnvelope.d.ts +33 -13
  43. package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
  44. package/_types/tempo/index.d.ts +22 -0
  45. package/_types/tempo/index.d.ts.map +1 -1
  46. package/_types/version.d.ts +1 -1
  47. package/core/AbiParameters.ts +3 -1
  48. package/core/internal/abiParameters.ts +17 -2
  49. package/core/internal/rpcSchemas/eth.ts +16 -0
  50. package/package.json +16 -1
  51. package/tempo/EarnShares/package.json +6 -0
  52. package/tempo/EarnShares.test.ts +122 -0
  53. package/tempo/EarnShares.ts +232 -0
  54. package/tempo/KeyAuthorization.test-d/package.json +6 -0
  55. package/tempo/KeyAuthorization.test-d.ts +62 -0
  56. package/tempo/KeyAuthorization.test.ts +132 -0
  57. package/tempo/KeyAuthorization.ts +76 -29
  58. package/tempo/MultisigConfig.test.ts +34 -2
  59. package/tempo/MultisigConfig.ts +18 -4
  60. package/tempo/SignatureEnvelope.test-d/package.json +6 -0
  61. package/tempo/SignatureEnvelope.test-d.ts +97 -0
  62. package/tempo/SignatureEnvelope.test.ts +227 -36
  63. package/tempo/SignatureEnvelope.ts +276 -85
  64. package/tempo/e2e.test.ts +0 -416
  65. package/tempo/index.ts +22 -0
  66. package/tempo/multisig.e2e.test.ts +582 -0
  67. package/version.ts +1 -1
@@ -72,10 +72,15 @@ export type GetType<
72
72
  userAddress: Address.Address
73
73
  }
74
74
  ? 'keychain'
75
- : envelope extends {
76
- account: Address.Address
77
- signatures: any
78
- }
75
+ : envelope extends
76
+ | {
77
+ account: Address.Address
78
+ signatures: any
79
+ }
80
+ | {
81
+ init: MultisigConfig.Config
82
+ signatures: any
83
+ }
79
84
  ? 'multisig'
80
85
  : never
81
86
 
@@ -117,6 +122,16 @@ export type SignatureEnvelopeRpc = OneOf<
117
122
  Secp256k1Rpc | P256Rpc | WebAuthnRpc | KeychainRpc | MultisigRpc
118
123
  >
119
124
 
125
+ /** Primitive signature envelope accepted by protocol sidecars. */
126
+ export type Primitive<bigintType = bigint, numberType = number> = OneOf<
127
+ | Secp256k1<bigintType, numberType>
128
+ | P256<bigintType, numberType>
129
+ | WebAuthn<bigintType, numberType>
130
+ >
131
+
132
+ /** RPC-formatted primitive signature envelope. */
133
+ export type PrimitiveRpc = OneOf<Secp256k1Rpc | P256Rpc | WebAuthnRpc>
134
+
120
135
  /**
121
136
  * Keychain signature version.
122
137
  *
@@ -174,16 +189,25 @@ export type Multisig<bigintType = bigint, numberType = number> = {
174
189
  init?: MultisigConfig.Config<numberType> | undefined
175
190
  }
176
191
 
177
- export type MultisigRpc = {
178
- type: 'multisig'
179
- account: Address.Address
180
- /**
181
- * Encoded owner approvals (raw serialized signatures), matching the node's
182
- * `Vec<Bytes>` representation.
183
- */
184
- signatures: readonly Serialized[]
185
- init?: MultisigConfig.Config | undefined
186
- }
192
+ /** RPC-formatted native multisig signature. */
193
+ export type MultisigRpc = OneOf<
194
+ | {
195
+ /** Existing native multisig account. */
196
+ account: Address.Address
197
+ /** Structured owner approvals. */
198
+ signatures: readonly SignatureEnvelopeRpc[]
199
+ /** Multisig RPC signatures are untagged. */
200
+ type?: undefined
201
+ }
202
+ | {
203
+ /** Initial config for bootstrapping a native multisig account. */
204
+ init: MultisigConfig.Config
205
+ /** Structured owner approvals. */
206
+ signatures: readonly SignatureEnvelopeRpc[]
207
+ /** Multisig RPC signatures are untagged. */
208
+ type?: undefined
209
+ }
210
+ >
187
211
 
188
212
  export type P256<bigintType = bigint, numberType = number> = {
189
213
  prehash: boolean
@@ -327,27 +351,7 @@ export function assert(envelope: PartialBy<SignatureEnvelope, 'type'>): void {
327
351
 
328
352
  if (type === 'multisig') {
329
353
  const multisig = envelope as Multisig
330
- const missing: string[] = []
331
- if (!multisig.account) missing.push('account')
332
- if (!Array.isArray(multisig.signatures)) missing.push('signatures')
333
- if (missing.length > 0)
334
- throw new MissingPropertiesError({ envelope, missing, type: 'multisig' })
335
- if (getNestingDepth(multisig) > MultisigConfig.maxNestingDepth)
336
- throw new InvalidMultisigApprovalError({
337
- reason: `multisig nesting depth exceeds ${MultisigConfig.maxNestingDepth}`,
338
- })
339
- for (const inner of multisig.signatures) {
340
- if (inner.type === 'keychain')
341
- throw new InvalidMultisigApprovalError({
342
- reason: 'keychain owner approvals are not allowed',
343
- })
344
- if (inner.type === 'multisig' && inner.init)
345
- throw new InvalidMultisigApprovalError({
346
- reason: 'nested multisig owner approvals cannot carry `init`',
347
- })
348
- assert(inner)
349
- }
350
- if (multisig.init) MultisigConfig.assert(multisig.init)
354
+ assertMultisig(multisig, 1)
351
355
  return
352
356
  }
353
357
  }
@@ -358,17 +362,75 @@ export declare namespace assert {
358
362
  | InvalidMultisigApprovalError
359
363
  | MissingPropertiesError
360
364
  | MultisigConfig.assert.ErrorType
365
+ | MultisigConfig.getAddress.ErrorType
361
366
  | Signature.assert.ErrorType
362
367
  | Errors.GlobalErrorType
363
368
  }
364
369
 
365
- // Returns the deepest multisig path length within a multisig envelope.
366
- function getNestingDepth(envelope: Multisig): number {
367
- let deepest = 0
368
- for (const inner of envelope.signatures)
369
- if (inner.type === 'multisig')
370
- deepest = Math.max(deepest, getNestingDepth(inner))
371
- return 1 + deepest
370
+ function assertMultisig(envelope: Multisig, depth: number): void {
371
+ const missing: string[] = []
372
+ if (!envelope.account) missing.push('account')
373
+ if (!Array.isArray(envelope.signatures)) missing.push('signatures')
374
+ if (missing.length > 0)
375
+ throw new MissingPropertiesError({
376
+ envelope,
377
+ missing,
378
+ type: 'multisig',
379
+ })
380
+ if (depth > MultisigConfig.maxNestingDepth)
381
+ throw new InvalidMultisigApprovalError({
382
+ reason: `multisig nesting depth exceeds ${MultisigConfig.maxNestingDepth}`,
383
+ })
384
+ if (!Address.validate(envelope.account))
385
+ throw new InvalidMultisigApprovalError({
386
+ reason: 'multisig account is invalid',
387
+ })
388
+ if (Hex.toBigInt(envelope.account) === 0n)
389
+ throw new InvalidMultisigApprovalError({
390
+ reason: 'multisig account cannot be zero',
391
+ })
392
+ if (envelope.signatures.length === 0)
393
+ throw new InvalidMultisigApprovalError({
394
+ reason: 'multisig signatures cannot be empty',
395
+ })
396
+ if (envelope.signatures.length > MultisigConfig.maxSignatures)
397
+ throw new InvalidMultisigApprovalError({
398
+ reason: `multisig signatures exceed ${MultisigConfig.maxSignatures}`,
399
+ })
400
+
401
+ if (envelope.init) {
402
+ MultisigConfig.assert(envelope.init)
403
+ if (
404
+ !Address.isEqual(
405
+ MultisigConfig.getAddress(envelope.init),
406
+ envelope.account,
407
+ )
408
+ )
409
+ throw new InvalidMultisigApprovalError({
410
+ reason: 'multisig init does not derive account',
411
+ })
412
+ }
413
+
414
+ for (const inner of envelope.signatures) {
415
+ const type = getType(inner)
416
+ if (type === 'keychain')
417
+ throw new InvalidMultisigApprovalError({
418
+ reason: 'keychain owner approvals are not allowed',
419
+ })
420
+ if (type === 'multisig') {
421
+ const multisig = inner as Multisig
422
+ if (multisig.init)
423
+ throw new InvalidMultisigApprovalError({
424
+ reason: 'nested multisig owner approvals cannot carry `init`',
425
+ })
426
+ assertMultisig(multisig, depth + 1)
427
+ } else assert(inner)
428
+
429
+ if (Hex.size(serialize(inner)) > MultisigConfig.maxOwnerSignatureBytes)
430
+ throw new InvalidMultisigApprovalError({
431
+ reason: `multisig owner signature exceeds ${MultisigConfig.maxOwnerSignatureBytes} bytes`,
432
+ })
433
+ }
372
434
  }
373
435
 
374
436
  /**
@@ -516,6 +578,13 @@ export declare namespace extractPublicKey {
516
578
  * @throws `CoercionError` if the serialized value cannot be coerced to a valid signature envelope.
517
579
  */
518
580
  export function deserialize(value: Serialized): SignatureEnvelope {
581
+ return deserialize_(value, 0)
582
+ }
583
+
584
+ function deserialize_(
585
+ value: Serialized,
586
+ multisigDepth: number,
587
+ ): SignatureEnvelope {
519
588
  const serialized = value.endsWith(magicBytes.slice(2))
520
589
  ? Hex.slice(value, 0, -Hex.size(magicBytes))
521
590
  : value
@@ -626,7 +695,7 @@ export function deserialize(value: Serialized): SignatureEnvelope {
626
695
  typeId === serializedKeychainV2Type
627
696
  ) {
628
697
  const userAddress = Hex.slice(data, 0, 20)
629
- const inner = deserialize(Hex.slice(data, 20))
698
+ const inner = deserialize_(Hex.slice(data, 20), multisigDepth)
630
699
 
631
700
  return {
632
701
  userAddress,
@@ -637,28 +706,91 @@ export function deserialize(value: Serialized): SignatureEnvelope {
637
706
  }
638
707
 
639
708
  if (typeId === serializedMultisigType) {
640
- // Wire format: `0x05 || rlp([account, signatures, init?])`. `init` is a
641
- // trailing optional: the bootstrap config list when present, otherwise
642
- // omitted entirely (the empty `0x80` placeholder is rejected).
643
- const [account, signatures, init] = Rlp.toHex(data) as [
644
- Hex.Hex,
645
- readonly Hex.Hex[],
646
- (Hex.Hex | MultisigConfig.Tuple)?,
647
- ]
648
- if (typeof init !== 'undefined' && !Array.isArray(init))
709
+ const depth = multisigDepth + 1
710
+ if (depth > MultisigConfig.maxNestingDepth)
649
711
  throw new InvalidSerializedError({
650
- reason:
651
- 'Invalid multisig `init`: expected the bootstrap config list or an omitted trailing element',
712
+ reason: `multisig nesting depth exceeds ${MultisigConfig.maxNestingDepth}`,
652
713
  serialized,
653
714
  })
654
- return {
715
+
716
+ // The first field distinguishes the static wire shapes: a bootstrap init
717
+ // config is an RLP list, while an initialized account is a 20-byte string.
718
+ const decoded = Rlp.toHex(data)
719
+ if (!Array.isArray(decoded) || decoded.length !== 2)
720
+ throw new InvalidSerializedError({
721
+ reason: 'invalid multisig wire shape: expected exactly two fields',
722
+ serialized,
723
+ })
724
+
725
+ const [address, signatures] = decoded
726
+ if (!Array.isArray(signatures) || signatures.some(Array.isArray))
727
+ throw new InvalidSerializedError({
728
+ reason: 'invalid multisig signatures list',
729
+ serialized,
730
+ })
731
+ if (signatures.length === 0)
732
+ throw new InvalidSerializedError({
733
+ reason: 'multisig signatures cannot be empty',
734
+ serialized,
735
+ })
736
+ if (signatures.length > MultisigConfig.maxSignatures)
737
+ throw new InvalidSerializedError({
738
+ reason: `multisig signatures exceed ${MultisigConfig.maxSignatures}`,
739
+ serialized,
740
+ })
741
+ for (const signature of signatures)
742
+ if (
743
+ Hex.size(signature as Hex.Hex) > MultisigConfig.maxOwnerSignatureBytes
744
+ )
745
+ throw new InvalidSerializedError({
746
+ reason: `multisig owner signature exceeds ${MultisigConfig.maxOwnerSignatureBytes} bytes`,
747
+ serialized,
748
+ })
749
+
750
+ if (!Array.isArray(address) && !Address.validate(address))
751
+ throw new InvalidSerializedError({
752
+ reason: 'invalid multisig account',
753
+ serialized,
754
+ })
755
+ if (Array.isArray(address)) {
756
+ const [salt, threshold, owners] = address
757
+ if (
758
+ address.length !== 3 ||
759
+ Array.isArray(salt) ||
760
+ Hex.size(salt) !== 32 ||
761
+ Array.isArray(threshold) ||
762
+ Hex.size(threshold) > 1 ||
763
+ !Array.isArray(owners) ||
764
+ owners.some(
765
+ (owner) =>
766
+ !Array.isArray(owner) ||
767
+ owner.length !== 2 ||
768
+ owner.some(Array.isArray) ||
769
+ Hex.size(owner[1] as Hex.Hex) > 1,
770
+ )
771
+ )
772
+ throw new InvalidSerializedError({
773
+ reason: 'invalid multisig init config',
774
+ serialized,
775
+ })
776
+ }
777
+
778
+ const init = Array.isArray(address)
779
+ ? MultisigConfig.fromTuple(address as unknown as MultisigConfig.Tuple)
780
+ : undefined
781
+ const account = init
782
+ ? MultisigConfig.getAddress(init)
783
+ : (address as Address.Address)
784
+ const envelope = {
655
785
  type: 'multisig',
656
786
  account,
657
- signatures: signatures.map((signature) => deserialize(signature)),
658
- ...(init
659
- ? { init: MultisigConfig.fromTuple(init as MultisigConfig.Tuple) }
660
- : {}),
787
+ signatures: signatures.map((signature) =>
788
+ deserialize_(signature as Hex.Hex, depth),
789
+ ),
790
+ ...(init ? { init } : {}),
661
791
  } satisfies Multisig
792
+ assertMultisig(envelope, depth)
793
+ return envelope
662
794
  }
663
795
 
664
796
  throw new InvalidSerializedError({
@@ -1048,19 +1180,28 @@ export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
1048
1180
  }
1049
1181
 
1050
1182
  if (
1051
- envelope.type === 'multisig' ||
1052
- ('account' in envelope && 'signatures' in envelope)
1183
+ (envelope as { type?: string | undefined }).type === 'multisig' ||
1184
+ ('signatures' in envelope && ('account' in envelope || 'init' in envelope))
1053
1185
  ) {
1054
1186
  const multisig = envelope as MultisigRpc
1055
- return {
1187
+ const hasAccount = typeof multisig.account !== 'undefined'
1188
+ const hasInit = typeof multisig.init !== 'undefined'
1189
+ if (hasAccount === hasInit)
1190
+ throw new InvalidMultisigApprovalError({
1191
+ reason: 'RPC multisig must contain exactly one of `account` or `init`',
1192
+ })
1193
+ const init = hasInit
1194
+ ? MultisigConfig.from(multisig.init as MultisigConfig.Config)
1195
+ : undefined
1196
+ const account = init ? MultisigConfig.getAddress(init) : multisig.account
1197
+ const result = {
1056
1198
  type: 'multisig',
1057
- account: multisig.account,
1058
- // Owner approvals are raw serialized signatures (node `Vec<Bytes>`).
1059
- signatures: multisig.signatures.map((signature) =>
1060
- deserialize(signature),
1061
- ),
1062
- ...(multisig.init ? { init: MultisigConfig.from(multisig.init) } : {}),
1063
- }
1199
+ account: account as Address.Address,
1200
+ signatures: multisig.signatures.map((signature) => fromRpc(signature)),
1201
+ ...(init ? { init } : {}),
1202
+ } satisfies Multisig
1203
+ assert(result)
1204
+ return result
1064
1205
  }
1065
1206
 
1066
1207
  throw new CoercionError({ envelope })
@@ -1068,8 +1209,10 @@ export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
1068
1209
 
1069
1210
  export declare namespace fromRpc {
1070
1211
  type ErrorType =
1212
+ | assert.ErrorType
1071
1213
  | CoercionError
1072
1214
  | InvalidSerializedError
1215
+ | MultisigConfig.getAddress.ErrorType
1073
1216
  | Signature.fromRpc.ErrorType
1074
1217
  | Errors.GlobalErrorType
1075
1218
  }
@@ -1141,7 +1284,9 @@ export function getType<
1141
1284
 
1142
1285
  // Detect Multisig signature
1143
1286
  if (
1144
- ('account' in envelope || 'genesisConfig' in envelope) &&
1287
+ ('account' in envelope ||
1288
+ 'genesisConfig' in envelope ||
1289
+ 'init' in envelope) &&
1145
1290
  'signatures' in envelope
1146
1291
  )
1147
1292
  return 'multisig' as never
@@ -1160,6 +1305,7 @@ export function getType<
1160
1305
  * - WebAuthn: `0x02` + webauthnData (variable) + r (32) + s (32) + pubKeyX (32) + pubKeyY (32)
1161
1306
  * - Keychain V1: `0x03` + userAddress (20) + inner signature (recursive)
1162
1307
  * - Keychain V2: `0x04` + userAddress (20) + inner signature (recursive)
1308
+ * - Multisig: `0x05` + RLP `[account | init, signatures]`
1163
1309
  *
1164
1310
  * [Signature Types](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types)
1165
1311
  *
@@ -1241,15 +1387,16 @@ export function serialize(
1241
1387
 
1242
1388
  if (type === 'multisig') {
1243
1389
  const multisig = envelope as Multisig
1244
- // Format: `0x05 || rlp([account, signatures, init?])`, where each owner
1245
- // approval is an encoded signature. `init` is a trailing optional: the
1246
- // bootstrap config list when present, otherwise omitted entirely.
1390
+ assert(multisig)
1391
+ // The first field is either the initialized account or the bootstrap init
1392
+ // config. Each owner approval is an encoded signature.
1247
1393
  return Hex.concat(
1248
1394
  serializedMultisigType,
1249
1395
  Rlp.fromHex([
1250
- multisig.account,
1396
+ multisig.init
1397
+ ? MultisigConfig.toTuple(multisig.init)
1398
+ : multisig.account,
1251
1399
  multisig.signatures.map((signature) => serialize(signature)),
1252
- ...(multisig.init ? [MultisigConfig.toTuple(multisig.init)] : []),
1253
1400
  ]),
1254
1401
  options.magic ? magicBytes : '0x',
1255
1402
  )
@@ -1266,6 +1413,16 @@ export declare namespace serialize {
1266
1413
  */
1267
1414
  magic?: boolean | undefined
1268
1415
  }
1416
+
1417
+ type ErrorType =
1418
+ | assert.ErrorType
1419
+ | CoercionError
1420
+ | Hex.concat.ErrorType
1421
+ | Hex.fromNumber.ErrorType
1422
+ | Hex.fromString.ErrorType
1423
+ | Rlp.fromHex.ErrorType
1424
+ | Signature.toHex.ErrorType
1425
+ | Errors.GlobalErrorType
1269
1426
  }
1270
1427
 
1271
1428
  /**
@@ -1376,7 +1533,9 @@ export declare namespace sortMultisigApprovals {
1376
1533
  * @param envelope - The signature envelope to convert.
1377
1534
  * @returns The RPC signature envelope with hex values.
1378
1535
  */
1379
- export function toRpc(envelope: SignatureEnvelope): SignatureEnvelopeRpc {
1536
+ export function toRpc<const envelope extends toRpc.Input>(
1537
+ envelope: envelope,
1538
+ ): toRpc.ReturnType<envelope> {
1380
1539
  const type = getType(envelope)
1381
1540
 
1382
1541
  if (type === 'secp256k1') {
@@ -1384,7 +1543,7 @@ export function toRpc(envelope: SignatureEnvelope): SignatureEnvelopeRpc {
1384
1543
  return {
1385
1544
  ...Signature.toRpc(secp256k1.signature),
1386
1545
  type: 'secp256k1',
1387
- }
1546
+ } as never
1388
1547
  }
1389
1548
 
1390
1549
  if (type === 'p256') {
@@ -1396,7 +1555,7 @@ export function toRpc(envelope: SignatureEnvelope): SignatureEnvelopeRpc {
1396
1555
  r: Hex.fromNumber(p256.signature.r, { size: 32 }),
1397
1556
  s: Hex.fromNumber(p256.signature.s, { size: 32 }),
1398
1557
  type: 'p256',
1399
- }
1558
+ } as never
1400
1559
  }
1401
1560
 
1402
1561
  if (type === 'webAuthn') {
@@ -1413,7 +1572,7 @@ export function toRpc(envelope: SignatureEnvelope): SignatureEnvelopeRpc {
1413
1572
  s: Hex.fromNumber(webauthn.signature.s, { size: 32 }),
1414
1573
  type: 'webAuthn',
1415
1574
  webauthnData,
1416
- }
1575
+ } as never
1417
1576
  }
1418
1577
 
1419
1578
  if (type === 'keychain') {
@@ -1424,25 +1583,57 @@ export function toRpc(envelope: SignatureEnvelope): SignatureEnvelopeRpc {
1424
1583
  signature: toRpc(keychain.inner),
1425
1584
  ...(keychain.keyId ? { keyId: keychain.keyId } : {}),
1426
1585
  ...(keychain.version ? { version: keychain.version } : {}),
1427
- }
1586
+ } as never
1428
1587
  }
1429
1588
 
1430
1589
  if (type === 'multisig') {
1431
1590
  const multisig = envelope as Multisig
1591
+ assert(multisig)
1592
+ const signatures = multisig.signatures.map((signature) => toRpc(signature))
1593
+ if (multisig.init) {
1594
+ const init = {
1595
+ ...multisig.init,
1596
+ salt: multisig.init.salt ?? MultisigConfig.zeroSalt,
1597
+ threshold: Number(multisig.init.threshold),
1598
+ owners: multisig.init.owners.map((owner) => ({
1599
+ ...owner,
1600
+ weight: Number(owner.weight),
1601
+ })),
1602
+ }
1603
+ return {
1604
+ init,
1605
+ signatures,
1606
+ } as never
1607
+ }
1432
1608
  return {
1433
- type: 'multisig',
1434
1609
  account: multisig.account,
1435
- // Owner approvals are raw serialized signatures (node `Vec<Bytes>`).
1436
- signatures: multisig.signatures.map((signature) => serialize(signature)),
1437
- ...(multisig.init ? { init: multisig.init } : {}),
1438
- }
1610
+ signatures,
1611
+ } as never
1439
1612
  }
1440
1613
 
1441
1614
  throw new CoercionError({ envelope })
1442
1615
  }
1443
1616
 
1444
1617
  export declare namespace toRpc {
1618
+ /** Input accepted by {@link ox#SignatureEnvelope.(toRpc:function)}. */
1619
+ type Input = SignatureEnvelope
1620
+
1621
+ /** RPC signature envelope inferred from the input type. */
1622
+ type ReturnType<envelope extends Input = Input> =
1623
+ GetType<envelope> extends 'secp256k1'
1624
+ ? Secp256k1Rpc
1625
+ : GetType<envelope> extends 'p256'
1626
+ ? P256Rpc
1627
+ : GetType<envelope> extends 'webAuthn'
1628
+ ? WebAuthnRpc
1629
+ : GetType<envelope> extends 'keychain'
1630
+ ? KeychainRpc
1631
+ : GetType<envelope> extends 'multisig'
1632
+ ? MultisigRpc
1633
+ : SignatureEnvelopeRpc
1634
+
1445
1635
  type ErrorType =
1636
+ | assert.ErrorType
1446
1637
  | CoercionError
1447
1638
  | Signature.toRpc.ErrorType
1448
1639
  | Errors.GlobalErrorType