ox 1.6.2 → 1.6.3

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 (40) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/tempo/KeyAuthorization.d.ts +16 -12
  3. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  4. package/dist/tempo/KeyAuthorization.js +7 -13
  5. package/dist/tempo/KeyAuthorization.js.map +1 -1
  6. package/dist/tempo/MultisigConfig.d.ts +20 -17
  7. package/dist/tempo/MultisigConfig.d.ts.map +1 -1
  8. package/dist/tempo/MultisigConfig.js +17 -16
  9. package/dist/tempo/MultisigConfig.js.map +1 -1
  10. package/dist/tempo/SignatureEnvelope.d.ts +19 -17
  11. package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
  12. package/dist/tempo/SignatureEnvelope.js +35 -27
  13. package/dist/tempo/SignatureEnvelope.js.map +1 -1
  14. package/dist/tempo/index.d.ts +2 -2
  15. package/dist/tempo/index.js +2 -2
  16. package/dist/zod/tempo/KeyAuthorization.d.ts +231 -22
  17. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  18. package/dist/zod/tempo/KeyAuthorization.js +10 -2
  19. package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
  20. package/dist/zod/tempo/RpcSchemaTempo.d.ts +82 -8
  21. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  22. package/dist/zod/tempo/Transaction.d.ts +246 -24
  23. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  24. package/dist/zod/tempo/TransactionRequest.d.ts +149 -14
  25. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  26. package/dist/zod/tempo/TxEnvelopeTempo.d.ts +78 -6
  27. package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/tempo/KeyAuthorization.test-d.ts +41 -6
  30. package/src/tempo/KeyAuthorization.test.ts +77 -18
  31. package/src/tempo/KeyAuthorization.ts +36 -36
  32. package/src/tempo/MultisigConfig.test.ts +28 -8
  33. package/src/tempo/MultisigConfig.ts +28 -19
  34. package/src/tempo/SignatureEnvelope.test.ts +64 -19
  35. package/src/tempo/SignatureEnvelope.ts +45 -35
  36. package/src/tempo/index.ts +2 -2
  37. package/src/tempo/multisig.e2e.test.ts +402 -145
  38. package/src/version.ts +1 -1
  39. package/src/zod/tempo/KeyAuthorization.ts +12 -2
  40. package/src/zod/tempo/_test/KeyAuthorization.test.ts +19 -5
@@ -1116,7 +1116,7 @@ describe('from', () => {
1116
1116
  })
1117
1117
 
1118
1118
  describe('multisig', () => {
1119
- const genesisConfig = MultisigConfig.from({
1119
+ const initialConfig = MultisigConfig.from({
1120
1120
  threshold: 1,
1121
1121
  owners: [
1122
1122
  {
@@ -1126,29 +1126,29 @@ describe('from', () => {
1126
1126
  ],
1127
1127
  })
1128
1128
 
1129
- test('behavior: derives `account` from `genesisConfig`', () => {
1129
+ test('behavior: derives `account` from `initialConfig`', () => {
1130
1130
  const envelope = SignatureEnvelope.from({
1131
- genesisConfig,
1131
+ initialConfig,
1132
1132
  signatures: [SignatureEnvelope.from(signature_secp256k1)],
1133
1133
  })
1134
1134
 
1135
1135
  expect(envelope).toMatchObject({
1136
1136
  type: 'multisig',
1137
- account: MultisigConfig.getAddress(genesisConfig),
1137
+ account: MultisigConfig.getAddress(initialConfig),
1138
1138
  })
1139
- expect('genesisConfig' in envelope).toBe(false)
1139
+ expect('initialConfig' in envelope).toBe(false)
1140
1140
  expect((envelope as SignatureEnvelope.Multisig).init).toBeUndefined()
1141
1141
  })
1142
1142
 
1143
- test('behavior: `init: true` opts into bootstrap (uses `genesisConfig` as `init`)', () => {
1143
+ test('behavior: `init: true` opts into bootstrap (uses `initialConfig` as `init`)', () => {
1144
1144
  const envelope = SignatureEnvelope.from({
1145
- genesisConfig,
1145
+ initialConfig,
1146
1146
  signatures: [SignatureEnvelope.from(signature_secp256k1)],
1147
1147
  init: true,
1148
1148
  })
1149
1149
 
1150
1150
  expect((envelope as SignatureEnvelope.Multisig).init).toEqual(
1151
- genesisConfig,
1151
+ initialConfig,
1152
1152
  )
1153
1153
  })
1154
1154
 
@@ -1163,7 +1163,7 @@ describe('from', () => {
1163
1163
  ],
1164
1164
  })
1165
1165
  const envelope = SignatureEnvelope.from({
1166
- genesisConfig,
1166
+ initialConfig,
1167
1167
  signatures: [SignatureEnvelope.from(signature_secp256k1)],
1168
1168
  init: otherConfig,
1169
1169
  })
@@ -1172,7 +1172,7 @@ describe('from', () => {
1172
1172
  })
1173
1173
 
1174
1174
  test('behavior: `{ account }` form still works', () => {
1175
- const account = MultisigConfig.getAddress(genesisConfig)
1175
+ const account = MultisigConfig.getAddress(initialConfig)
1176
1176
  const envelope = SignatureEnvelope.from({
1177
1177
  account,
1178
1178
  signatures: [SignatureEnvelope.from(signature_secp256k1)],
@@ -1793,7 +1793,7 @@ describe('serialize', () => {
1793
1793
  })
1794
1794
 
1795
1795
  describe('sortMultisigApprovals', () => {
1796
- // Build owner key pairs first so we can construct a real genesis config
1796
+ // Build owner key pairs first so we can construct a real initial config
1797
1797
  // whose owner set matches the keys that produce the approvals below.
1798
1798
  const ownerKeys = Array.from({ length: 3 }, () => {
1799
1799
  const privateKey = Secp256k1.randomPrivateKey()
@@ -1806,12 +1806,15 @@ describe('sortMultisigApprovals', () => {
1806
1806
  Hex.toBigInt(a.address) < Hex.toBigInt(b.address) ? -1 : 1,
1807
1807
  )
1808
1808
 
1809
- const genesisConfig = MultisigConfig.from({
1809
+ const initialConfig = MultisigConfig.from({
1810
1810
  threshold: 2,
1811
1811
  owners: ascendingOwners.map((o) => ({ owner: o.address, weight: 1 })),
1812
1812
  })
1813
1813
  const payload = `0x${'42'.repeat(32)}` as const
1814
- const digest = MultisigConfig.getSignPayload({ payload, genesisConfig })
1814
+ const digest = MultisigConfig.getSignPayload({
1815
+ payload,
1816
+ initialConfig,
1817
+ })
1815
1818
 
1816
1819
  const owners = ownerKeys.map((owner) => ({
1817
1820
  address: owner.address,
@@ -1826,7 +1829,7 @@ describe('sortMultisigApprovals', () => {
1826
1829
 
1827
1830
  test('behavior: orders approvals ascending by recovered owner address', () => {
1828
1831
  const ordered = SignatureEnvelope.sortMultisigApprovals({
1829
- genesisConfig,
1832
+ initialConfig,
1830
1833
  payload,
1831
1834
  // Provide approvals in reverse of the canonical order.
1832
1835
  signatures: [...ascending].reverse().map((owner) => owner.signature),
@@ -1838,7 +1841,7 @@ describe('sortMultisigApprovals', () => {
1838
1841
  const signatures = ascending.map((owner) => owner.signature)
1839
1842
  expect(
1840
1843
  SignatureEnvelope.sortMultisigApprovals({
1841
- genesisConfig,
1844
+ initialConfig,
1842
1845
  payload,
1843
1846
  signatures,
1844
1847
  }),
@@ -1847,7 +1850,7 @@ describe('sortMultisigApprovals', () => {
1847
1850
 
1848
1851
  test('behavior: recovered order matches the config owner order', () => {
1849
1852
  const ordered = SignatureEnvelope.sortMultisigApprovals({
1850
- genesisConfig,
1853
+ initialConfig,
1851
1854
  payload,
1852
1855
  signatures: owners.map((owner) => owner.signature),
1853
1856
  })
@@ -1857,12 +1860,12 @@ describe('sortMultisigApprovals', () => {
1857
1860
  expect(recovered).toEqual(ascending.map((owner) => owner.address))
1858
1861
  })
1859
1862
 
1860
- test('behavior: `genesisConfig` and `{ account }` produce identical ordering', () => {
1861
- const account = MultisigConfig.getAddress(genesisConfig)
1863
+ test('behavior: `initialConfig` and `{ account }` produce identical ordering', () => {
1864
+ const account = MultisigConfig.getAddress(initialConfig)
1862
1865
  const signatures = owners.map((owner) => owner.signature)
1863
1866
 
1864
1867
  const fromConfig = SignatureEnvelope.sortMultisigApprovals({
1865
- genesisConfig,
1868
+ initialConfig,
1866
1869
  payload,
1867
1870
  signatures,
1868
1871
  })
@@ -3041,6 +3044,14 @@ describe('multisig', () => {
3041
3044
  ).toThrowErrorMatchingInlineSnapshot(
3042
3045
  `[SignatureEnvelope.InvalidMultisigApprovalError: Invalid native multisig owner approval: multisig owner signature exceeds 2049 bytes.]`,
3043
3046
  )
3047
+
3048
+ const serialized = Hex.concat(
3049
+ '0x05',
3050
+ Rlp.fromHex([account, [SignatureEnvelope.serialize(oversized)]]),
3051
+ )
3052
+ expect(() => SignatureEnvelope.deserialize(serialized)).toThrowError(
3053
+ SignatureEnvelope.InvalidSerializedError,
3054
+ )
3044
3055
  })
3045
3056
 
3046
3057
  test('assert: rejects keychain owner approvals', () => {
@@ -3082,6 +3093,40 @@ describe('multisig', () => {
3082
3093
  expect(() => SignatureEnvelope.assert(depth2)).not.toThrowError()
3083
3094
  })
3084
3095
 
3096
+ test('accepts a nested approval above the primitive byte limit', () => {
3097
+ const primitive = SignatureEnvelope.from({
3098
+ ...signature_webauthn,
3099
+ metadata: {
3100
+ ...signature_webauthn.metadata,
3101
+ clientDataJSON: JSON.stringify({ value: 'x'.repeat(1_050) }),
3102
+ },
3103
+ signature: {
3104
+ r: signature_webauthn.signature.r,
3105
+ s: signature_webauthn.signature.s,
3106
+ },
3107
+ })
3108
+ const largeNested = SignatureEnvelope.from({
3109
+ type: 'multisig',
3110
+ account: nestedAccount,
3111
+ signatures: [primitive, primitive],
3112
+ })
3113
+ expect(Hex.size(SignatureEnvelope.serialize(primitive))).toBeLessThan(
3114
+ MultisigConfig.maxOwnerSignatureBytes,
3115
+ )
3116
+ expect(
3117
+ Hex.size(SignatureEnvelope.serialize(largeNested)),
3118
+ ).toBeGreaterThan(MultisigConfig.maxOwnerSignatureBytes)
3119
+
3120
+ const parent = SignatureEnvelope.from({
3121
+ type: 'multisig',
3122
+ account,
3123
+ signatures: [largeNested],
3124
+ })
3125
+ expect(
3126
+ SignatureEnvelope.deserialize(SignatureEnvelope.serialize(parent)),
3127
+ ).toEqual(parent)
3128
+ })
3129
+
3085
3130
  test('assert: rejects nesting deeper than the maximum', () => {
3086
3131
  const depth3 = SignatureEnvelope.from({
3087
3132
  type: 'multisig',
@@ -434,12 +434,13 @@ function assertMultisig(envelope: Multisig, depth: number): void {
434
434
  reason: 'nested multisig owner approvals cannot carry `init`',
435
435
  })
436
436
  assertMultisig(multisig, depth + 1)
437
- } else assert(inner)
438
-
439
- if (Hex.size(serialize(inner)) > MultisigConfig.maxOwnerSignatureBytes)
440
- throw new InvalidMultisigApprovalError({
441
- reason: `multisig owner signature exceeds ${MultisigConfig.maxOwnerSignatureBytes} bytes`,
442
- })
437
+ } else {
438
+ assert(inner)
439
+ if (Hex.size(serialize(inner)) > MultisigConfig.maxOwnerSignatureBytes)
440
+ throw new InvalidMultisigApprovalError({
441
+ reason: `multisig owner signature exceeds ${MultisigConfig.maxOwnerSignatureBytes} bytes`,
442
+ })
443
+ }
443
444
  }
444
445
  }
445
446
 
@@ -750,7 +751,10 @@ function deserialize_(
750
751
  })
751
752
  for (const signature of signatures)
752
753
  if (
753
- Hex.size(signature as Hex.Hex) > MultisigConfig.maxOwnerSignatureBytes
754
+ Hex.size(signature as Hex.Hex) >
755
+ MultisigConfig.maxOwnerSignatureBytes &&
756
+ Hex.slice(signature as Hex.Hex, 0, 1) !==
757
+ MultisigConfig.signatureTypeByte
754
758
  )
755
759
  throw new InvalidSerializedError({
756
760
  reason: `multisig owner signature exceeds ${MultisigConfig.maxOwnerSignatureBytes} bytes`,
@@ -935,17 +939,17 @@ function deserialize_(
935
939
  * ```
936
940
  *
937
941
  * @example
938
- * ### Multisig (from genesis config)
942
+ * ### Multisig (from initial config)
939
943
  *
940
- * Pass `genesisConfig` to derive `account` automatically. Set `init: true` to
941
- * opt into bootstrap (uses `genesisConfig` as the bootstrap `init`); omit
944
+ * Pass `initialConfig` to derive `account` automatically. Set `init: true` to
945
+ * opt into bootstrap (uses `initialConfig` as the bootstrap `init`); omit
942
946
  * `init` for subsequent (non-bootstrap) transactions.
943
947
  *
944
948
  * ```ts twoslash
945
949
  * import { Secp256k1 } from 'ox'
946
950
  * import { MultisigConfig, SignatureEnvelope } from 'ox/tempo'
947
951
  *
948
- * const genesisConfig = MultisigConfig.from({
952
+ * const initialConfig = MultisigConfig.from({
949
953
  * threshold: 1,
950
954
  * owners: [
951
955
  * {
@@ -962,14 +966,14 @@ function deserialize_(
962
966
  *
963
967
  * // Bootstrap transaction
964
968
  * const bootstrap = SignatureEnvelope.from({
965
- * genesisConfig,
969
+ * initialConfig,
966
970
  * signatures: [signature],
967
971
  * init: true
968
972
  * })
969
973
  *
970
974
  * // Subsequent (non-bootstrap) transactions
971
975
  * const subsequent = SignatureEnvelope.from({
972
- * genesisConfig,
976
+ * initialConfig,
973
977
  * signatures: [signature]
974
978
  * })
975
979
  * ```
@@ -996,20 +1000,20 @@ export function from<const value extends from.Value>(
996
1000
 
997
1001
  if (type === 'multisig') {
998
1002
  const multisig = value as Multisig & {
999
- genesisConfig?: MultisigConfig.Config | undefined
1003
+ initialConfig?: MultisigConfig.Config | undefined
1000
1004
  init?: MultisigConfig.Config | boolean | undefined
1001
1005
  }
1002
- const { genesisConfig, init, ...rest } = multisig
1003
- // Derive `account` from `genesisConfig` when not provided explicitly.
1006
+ const { initialConfig, init, ...rest } = multisig
1007
+ // Derive `account` from `initialConfig` when not provided explicitly.
1004
1008
  const account = (() => {
1005
1009
  if (rest.account) return rest.account
1006
- if (genesisConfig) return MultisigConfig.getAddress(genesisConfig)
1010
+ if (initialConfig) return MultisigConfig.getAddress(initialConfig)
1007
1011
  return rest.account
1008
1012
  })()
1009
- // `init: true` opts into bootstrap using the supplied `genesisConfig`.
1013
+ // `init: true` opts into bootstrap using the supplied `initialConfig`.
1010
1014
  // Otherwise, `init` is treated as the explicit bootstrap config (or
1011
1015
  // omitted).
1012
- const initSource = init === true ? genesisConfig : init || undefined
1016
+ const initSource = init === true ? initialConfig : init || undefined
1013
1017
  return {
1014
1018
  ...rest,
1015
1019
  account,
@@ -1065,13 +1069,13 @@ export declare namespace from {
1065
1069
 
1066
1070
  /**
1067
1071
  * Multisig envelope input variant where `account` is derived from the
1068
- * supplied `genesisConfig`. Pass `init: true` to opt into bootstrap (uses
1069
- * `genesisConfig` as the bootstrap `init`); omit `init` for subsequent
1072
+ * supplied `initialConfig`. Pass `init: true` to opt into bootstrap (uses
1073
+ * `initialConfig` as the bootstrap `init`); omit `init` for subsequent
1070
1074
  * (non-bootstrap) transactions.
1071
1075
  */
1072
- type MultisigFromGenesisConfig = {
1076
+ type MultisigFromInitialConfig = {
1073
1077
  type?: 'multisig' | undefined
1074
- genesisConfig: MultisigConfig.Config
1078
+ initialConfig: MultisigConfig.Config
1075
1079
  signatures: readonly SignatureEnvelope[]
1076
1080
  init?: MultisigConfig.Config | boolean | undefined
1077
1081
  }
@@ -1080,7 +1084,7 @@ export declare namespace from {
1080
1084
  | UnionPartialBy<SignatureEnvelope, 'prehash' | 'type'>
1081
1085
  | Secp256k1Flat
1082
1086
  | Serialized
1083
- | MultisigFromGenesisConfig
1087
+ | MultisigFromInitialConfig
1084
1088
 
1085
1089
  type ReturnValue<value extends Value> = Compute<
1086
1090
  OneOf<
@@ -1088,7 +1092,7 @@ export declare namespace from {
1088
1092
  ? SignatureEnvelope
1089
1093
  : value extends Secp256k1Flat
1090
1094
  ? Secp256k1
1091
- : value extends MultisigFromGenesisConfig
1095
+ : value extends MultisigFromInitialConfig
1092
1096
  ? Multisig
1093
1097
  : IsNarrowable<value, SignatureEnvelope> extends true
1094
1098
  ? SignatureEnvelope
@@ -1315,7 +1319,7 @@ export function getType<
1315
1319
  // Detect Multisig signature
1316
1320
  if (
1317
1321
  ('account' in envelope ||
1318
- 'genesisConfig' in envelope ||
1322
+ 'initialConfig' in envelope ||
1319
1323
  'init' in envelope) &&
1320
1324
  'signatures' in envelope
1321
1325
  )
@@ -1470,7 +1474,7 @@ export declare namespace serialize {
1470
1474
  * recovered owner address. Works for any owner key type (secp256k1, p256,
1471
1475
  * webAuthn).
1472
1476
  *
1473
- * Config updates never change `account`, so the genesis config is the correct
1477
+ * Config updates never change `account`, so the initial config is the correct
1474
1478
  * input even for post-update transactions.
1475
1479
  *
1476
1480
  * @example
@@ -1482,7 +1486,7 @@ export declare namespace serialize {
1482
1486
  * TxEnvelopeTempo
1483
1487
  * } from 'ox/tempo'
1484
1488
  *
1485
- * const genesisConfig = MultisigConfig.from({
1489
+ * const initialConfig = MultisigConfig.from({
1486
1490
  * threshold: 2,
1487
1491
  * owners: [
1488
1492
  * {
@@ -1505,7 +1509,7 @@ export declare namespace serialize {
1505
1509
  * ]
1506
1510
  * const digest = MultisigConfig.getSignPayload({
1507
1511
  * payload,
1508
- * genesisConfig
1512
+ * initialConfig
1509
1513
  * })
1510
1514
  * const signatures = privateKeys.map((privateKey) =>
1511
1515
  * SignatureEnvelope.from(
@@ -1515,7 +1519,7 @@ export declare namespace serialize {
1515
1519
  *
1516
1520
  * const ordered = SignatureEnvelope.sortMultisigApprovals({
1517
1521
  * // [!code focus]
1518
- * genesisConfig, // [!code focus]
1522
+ * initialConfig, // [!code focus]
1519
1523
  * payload, // [!code focus]
1520
1524
  * signatures // [!code focus]
1521
1525
  * }) // [!code focus]
@@ -1527,11 +1531,15 @@ export declare namespace serialize {
1527
1531
  export function sortMultisigApprovals(
1528
1532
  value: sortMultisigApprovals.Value,
1529
1533
  ): readonly SignatureEnvelope[] {
1530
- const { payload, signatures } = value
1534
+ const { payload, signatures, version = 0n } = value
1531
1535
  const digest = MultisigConfig.getSignPayload(
1532
- 'genesisConfig' in value && value.genesisConfig
1533
- ? { payload, genesisConfig: value.genesisConfig }
1534
- : { payload, account: (value as { account: Address.Address }).account },
1536
+ 'initialConfig' in value && value.initialConfig
1537
+ ? { payload, initialConfig: value.initialConfig, version }
1538
+ : {
1539
+ payload,
1540
+ account: (value as { account: Address.Address }).account,
1541
+ version,
1542
+ },
1535
1543
  )
1536
1544
  // Recover each signer once (decorate–sort–undecorate) rather than inside the
1537
1545
  // comparator.
@@ -1550,6 +1558,8 @@ export declare namespace sortMultisigApprovals {
1550
1558
  payload: Hex.Hex | Bytes.Bytes
1551
1559
  /** The owner approvals to order. */
1552
1560
  signatures: readonly SignatureEnvelope[]
1561
+ /** Current multisig config version. Defaults to `0n`. */
1562
+ version?: bigint | undefined
1553
1563
  } & OneOf<
1554
1564
  | {
1555
1565
  /** The native multisig account address. */
@@ -1560,7 +1570,7 @@ export declare namespace sortMultisigApprovals {
1560
1570
  * The initial multisig config (the bootstrap config that derived the
1561
1571
  * permanent `account`). Used to derive the account automatically.
1562
1572
  */
1563
- genesisConfig: MultisigConfig.Config
1573
+ initialConfig: MultisigConfig.Config
1564
1574
  }
1565
1575
  >
1566
1576
 
@@ -153,7 +153,7 @@ export * as KeyAuthorization from './KeyAuthorization.js'
153
153
  * ```ts twoslash
154
154
  * import { MultisigConfig } from 'ox/tempo'
155
155
  *
156
- * const genesisConfig = MultisigConfig.from({
156
+ * const initialConfig = MultisigConfig.from({
157
157
  * threshold: 2,
158
158
  * owners: [
159
159
  * {
@@ -167,7 +167,7 @@ export * as KeyAuthorization from './KeyAuthorization.js'
167
167
  * ]
168
168
  * })
169
169
  *
170
- * const account = MultisigConfig.getAddress(genesisConfig)
170
+ * const account = MultisigConfig.getAddress(initialConfig)
171
171
  * ```
172
172
  *
173
173
  * @category Reference