ox 0.14.40 → 0.14.41

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.
@@ -15,14 +15,10 @@ export type Base<quantity = bigint> = {
15
15
  approvals: readonly Hex.Hex[]
16
16
  /** Root configuration used to verify approvals. */
17
17
  config: MultisigConfig.Config<quantity>
18
- /** Root configuration version. */
19
- configVersion: quantity
20
18
  /** Unix creation time in milliseconds. */
21
19
  createdAt: number
22
20
  /** Deterministic multisig operation hash. */
23
21
  hash: Hex.Hex
24
- /** Whether the operation initializes the root multisig account. */
25
- init: boolean
26
22
  /** Number of approvals selected for quorum evaluation. */
27
23
  signatureCount: number
28
24
  /** Required root owner weight. */
@@ -73,9 +69,6 @@ export type KeyAuthorizationRpc = KeyAuthorizationOperation<Hex.Hex>
73
69
  /** JSON-RPC multisig operation. */
74
70
  export type Rpc = Operation<Hex.Hex>
75
71
 
76
- /** Maximum supported multisig configuration version. */
77
- const maxConfigVersion = 2n ** 64n - 1n
78
-
79
72
  /**
80
73
  * Derives the deterministic hash for a multisig operation.
81
74
  *
@@ -86,7 +79,7 @@ const maxConfigVersion = 2n ** 64n - 1n
86
79
  *
87
80
  * const hash = MultisigOperation.getHash({
88
81
  * account,
89
- * configVersion: 1n,
82
+ * config,
90
83
  * transaction,
91
84
  * type: 'transaction',
92
85
  * })
@@ -96,7 +89,7 @@ const maxConfigVersion = 2n ** 64n - 1n
96
89
  * @returns The operation hash signed by each owner.
97
90
  */
98
91
  export function getHash(options: getHash.Options): Hex.Hex {
99
- const { account, configVersion } = options
92
+ const { account, config } = options
100
93
  const payload =
101
94
  options.type === 'transaction'
102
95
  ? TxEnvelopeTempo.getSignPayload(
@@ -109,7 +102,7 @@ export function getHash(options: getHash.Options): Hex.Hex {
109
102
  )
110
103
  return MultisigConfig.getSignPayload({
111
104
  account,
112
- config: { version: configVersion },
105
+ config,
113
106
  payload,
114
107
  })
115
108
  }
@@ -119,8 +112,8 @@ export declare namespace getHash {
119
112
  export type Options = {
120
113
  /** Root multisig account. */
121
114
  account: Address.Address
122
- /** Root configuration version. */
123
- configVersion: bigint
115
+ /** Complete root multisig configuration witness. */
116
+ config: MultisigConfig.Config
124
117
  } & (
125
118
  | {
126
119
  /** Canonical serialized key authorization. */
@@ -163,7 +156,6 @@ export declare namespace getHash {
163
156
  * approvals,
164
157
  * config,
165
158
  * hash,
166
- * resolveConfig,
167
159
  * })
168
160
  * ```
169
161
  *
@@ -173,18 +165,25 @@ export declare namespace getHash {
173
165
  export async function selectApprovals(
174
166
  options: selectApprovals.Options,
175
167
  ): Promise<selectApprovals.ReturnValue> {
176
- const { account, approvals, hash, resolveConfig } = options
168
+ const { account, approvals, hash } = options
177
169
  if (!Address.validate(account) || Hex.toBigInt(account) === 0n)
178
170
  throw new InvalidApprovalError({ reason: 'account is invalid' })
179
171
  if (!Hash.validate(hash))
180
172
  throw new InvalidApprovalError({ reason: 'hash is invalid' })
173
+ const config = MultisigConfig.from(options.config)
174
+ if (
175
+ config.version === 0n &&
176
+ !Address.isEqual(MultisigConfig.getAddress(config), account)
177
+ )
178
+ throw new InvalidApprovalError({
179
+ reason: 'initial config does not derive the root multisig account',
180
+ })
181
181
  return selectApprovals_internal(
182
182
  {
183
183
  account,
184
184
  approvals,
185
- config: MultisigConfig.from(options.config),
185
+ config,
186
186
  hash,
187
- resolveConfig,
188
187
  },
189
188
  [account.toLowerCase()],
190
189
  )
@@ -201,27 +200,6 @@ export declare namespace selectApprovals {
201
200
  config: MultisigConfig.Config
202
201
  /** Deterministic operation hash approved by root owners. */
203
202
  hash: Hex.Hex
204
- /** Resolves the current configuration of a nested multisig owner. */
205
- resolveConfig?: ResolveConfig | undefined
206
- }
207
-
208
- /** Resolves an initialized nested multisig configuration. */
209
- export type ResolveConfig = (
210
- options: ResolveConfigOptions,
211
- ) => ResolvedConfig | Promise<ResolvedConfig>
212
-
213
- /** Nested multisig configuration lookup parameters. */
214
- export type ResolveConfigOptions = {
215
- /** Nested multisig account. */
216
- account: Address.Address
217
- }
218
-
219
- /** Resolved nested multisig configuration. */
220
- export type ResolvedConfig = {
221
- /** Current nested multisig configuration. */
222
- config: MultisigConfig.Config
223
- /** Current nested multisig configuration version. */
224
- version: bigint
225
203
  }
226
204
 
227
205
  /** Result of validating and selecting approvals. */
@@ -339,10 +317,6 @@ export function from<const operation extends Operation>(
339
317
  ): from.ReturnValue<operation> {
340
318
  try {
341
319
  const config = MultisigConfig.from(operation.config)
342
- if (config.version !== operation.configVersion)
343
- throw new InvalidOperationError({
344
- reason: 'config.version must equal configVersion',
345
- })
346
320
  if (
347
321
  typeof config.threshold !== 'number' ||
348
322
  config.owners.some((owner) => typeof owner.weight !== 'number')
@@ -392,22 +366,19 @@ export function fromRpc<const operation extends Rpc>(
392
366
  operation: operation,
393
367
  ): fromRpc.ReturnValue<operation> {
394
368
  try {
395
- if (
396
- typeof operation.configVersion !== 'string' ||
397
- !Hex.validate(operation.configVersion)
398
- )
369
+ const version = operation.config?.version
370
+ if (typeof version !== 'string' || !Hex.validate(version))
399
371
  throw new InvalidOperationError({
400
- reason: 'configVersion must be a hexadecimal quantity',
372
+ reason: 'config.version must be a hexadecimal quantity',
401
373
  })
402
- const configVersion = Hex.toBigInt(operation.configVersion)
403
- if (Hex.fromNumber(configVersion) !== operation.configVersion)
374
+ const version_ = Hex.toBigInt(version)
375
+ if (Hex.fromNumber(version_) !== version)
404
376
  throw new InvalidOperationError({
405
- reason: 'configVersion must use canonical quantity encoding',
377
+ reason: 'config.version must use canonical quantity encoding',
406
378
  })
407
379
  return from({
408
380
  ...operation,
409
381
  config: MultisigConfig.fromRpc(operation.config),
410
- configVersion,
411
382
  } as Operation) as never
412
383
  } catch (cause) {
413
384
  if (cause instanceof InvalidOperationError) throw cause
@@ -447,7 +418,6 @@ export function toRpc<const operation extends Operation>(
447
418
  return {
448
419
  ...value,
449
420
  config: MultisigConfig.toRpc(value.config),
450
- configVersion: Hex.fromNumber(value.configVersion),
451
421
  } as never
452
422
  }
453
423
 
@@ -459,7 +429,7 @@ export declare namespace toRpc {
459
429
  : KeyAuthorizationRpc
460
430
 
461
431
  /** Error type for `toRpc`. */
462
- export type ErrorType = from.ErrorType | Hex.fromNumber.ErrorType
432
+ export type ErrorType = from.ErrorType | MultisigConfig.toRpc.ErrorType
463
433
  }
464
434
 
465
435
  /**
@@ -525,15 +495,17 @@ async function selectApprovals_internal(
525
495
  throw new InvalidApprovalError({
526
496
  reason: `nested multisig owner ${group.address} is invalid`,
527
497
  })
528
- if (!options.resolveConfig)
498
+ const config = MultisigConfig.from(nested[0]!.config)
499
+ if (nested.some((signature) => !sameConfig(signature.config, config)))
529
500
  throw new InvalidApprovalError({
530
- reason: `nested multisig owner ${group.address} requires a config resolver`,
501
+ reason: `nested multisig owner ${group.address} has conflicting config witnesses`,
531
502
  })
532
- const resolved = await options.resolveConfig({ account: group.address })
533
- const config = MultisigConfig.from(resolved.config)
534
- if (config.version !== resolved.version)
503
+ if (
504
+ config.version === 0n &&
505
+ !Address.isEqual(MultisigConfig.getAddress(config), group.address)
506
+ )
535
507
  throw new InvalidApprovalError({
536
- reason: `resolved config.version must equal version for nested multisig owner ${group.address}`,
508
+ reason: `initial config does not derive nested multisig owner ${group.address}`,
537
509
  })
538
510
  const selected = await selectApprovals_internal(
539
511
  {
@@ -549,7 +521,6 @@ async function selectApprovals_internal(
549
521
  config,
550
522
  payload: options.hash,
551
523
  }),
552
- resolveConfig: options.resolveConfig,
553
524
  },
554
525
  [...path, group.address.toLowerCase()],
555
526
  )
@@ -691,16 +662,6 @@ function assertBase(operation: Operation, config: MultisigConfig.Config): void {
691
662
  throw new InvalidOperationError({ reason: 'account cannot be zero' })
692
663
  if (!Hash.validate(operation.hash))
693
664
  throw new InvalidOperationError({ reason: 'hash is invalid' })
694
- if (typeof operation.init !== 'boolean')
695
- throw new InvalidOperationError({ reason: 'init must be a boolean' })
696
- if (
697
- typeof operation.configVersion !== 'bigint' ||
698
- operation.configVersion < 0n ||
699
- operation.configVersion > maxConfigVersion
700
- )
701
- throw new InvalidOperationError({
702
- reason: 'configVersion must be an unsigned 64-bit integer',
703
- })
704
665
  assertInteger(operation.createdAt, 'createdAt')
705
666
  assertInteger(operation.updatedAt, 'updatedAt')
706
667
  if (operation.updatedAt < operation.createdAt)
@@ -780,19 +741,13 @@ function assertBase(operation: Operation, config: MultisigConfig.Config): void {
780
741
  reason:
781
742
  'weight is not reachable by signatureCount retained owner approvals',
782
743
  })
783
- if (operation.init) {
784
- if (operation.configVersion !== 0n)
785
- throw new InvalidOperationError({
786
- reason: 'bootstrap operations must use config version zero',
787
- })
788
- if (
789
- MultisigConfig.getAddress(config).toLowerCase() !==
790
- operation.account.toLowerCase()
791
- )
792
- throw new InvalidOperationError({
793
- reason: 'bootstrap config does not derive the operation account',
794
- })
795
- }
744
+ if (
745
+ config.version === 0n &&
746
+ !Address.isEqual(MultisigConfig.getAddress(config), operation.account)
747
+ )
748
+ throw new InvalidOperationError({
749
+ reason: 'initial config does not derive the operation account',
750
+ })
796
751
  }
797
752
 
798
753
  /**
@@ -37,11 +37,11 @@ test('toRpc preserves the signature type', () => {
37
37
  test('MultisigRpc carries one complete witness shape', () => {
38
38
  const rpc = {
39
39
  account: '0x1111111111111111111111111111111111111111',
40
- config: MultisigConfig.toRpc(config),
40
+ config: { ...config, version: 0 },
41
41
  signatures: [signatureRpc],
42
42
  } as const satisfies SignatureEnvelope.MultisigRpc
43
43
 
44
- expectTypeOf(rpc.config).toMatchTypeOf<MultisigConfig.Rpc>()
44
+ expectTypeOf(rpc.config).toMatchTypeOf<MultisigConfig.Config<number>>()
45
45
  expectTypeOf(rpc.signatures).toMatchTypeOf<
46
46
  readonly SignatureEnvelope.SignatureEnvelopeRpc[]
47
47
  >()
@@ -92,7 +92,7 @@ test('MultisigRpc rejects old witness shapes', () => {
92
92
 
93
93
  const serialized = {
94
94
  account: '0x1111111111111111111111111111111111111111',
95
- config: MultisigConfig.toRpc(config),
95
+ config: { ...config, version: 0 },
96
96
  signatures: ['0x1234'],
97
97
  } as const
98
98
  // @ts-expect-error Owner approvals use structured RPC envelopes.
@@ -100,7 +100,7 @@ test('MultisigRpc rejects old witness shapes', () => {
100
100
 
101
101
  const tagged = {
102
102
  account: '0x1111111111111111111111111111111111111111',
103
- config: MultisigConfig.toRpc(config),
103
+ config: { ...config, version: 0 },
104
104
  signatures: [signatureRpc],
105
105
  type: 'multisig',
106
106
  } as const
@@ -3035,7 +3035,7 @@ describe('multisig', () => {
3035
3035
  ],
3036
3036
  "salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
3037
3037
  "threshold": 1,
3038
- "version": "0x1",
3038
+ "version": 1,
3039
3039
  },
3040
3040
  "signatures": [
3041
3041
  {
@@ -3057,7 +3057,7 @@ describe('multisig', () => {
3057
3057
  ],
3058
3058
  "salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
3059
3059
  "threshold": 1,
3060
- "version": "0x0",
3060
+ "version": 0,
3061
3061
  },
3062
3062
  "signatures": [
3063
3063
  {
@@ -245,7 +245,7 @@ export type MultisigRpc = {
245
245
  /** Native multisig account address. */
246
246
  account: Address.Address
247
247
  /** Complete applicable multisig configuration witness. */
248
- config: MultisigConfig.Rpc
248
+ config: MultisigConfig.Config<number>
249
249
  /** Structured owner approvals. */
250
250
  signatures: readonly SignatureEnvelopeRpc[]
251
251
  /** Multisig RPC signatures are untagged. */
@@ -1229,7 +1229,7 @@ export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
1229
1229
  const multisig = envelope as MultisigRpc
1230
1230
  const result = {
1231
1231
  account: multisig.account,
1232
- config: MultisigConfig.fromRpc(multisig.config),
1232
+ config: MultisigConfig.from(multisig.config),
1233
1233
  signatures: multisig.signatures.map((signature) => fromRpc(signature)),
1234
1234
  type: 'multisig',
1235
1235
  } satisfies Multisig
@@ -1245,7 +1245,7 @@ export declare namespace fromRpc {
1245
1245
  | assert.ErrorType
1246
1246
  | CoercionError
1247
1247
  | InvalidSerializedError
1248
- | MultisigConfig.fromRpc.ErrorType
1248
+ | MultisigConfig.assert.ErrorType
1249
1249
  | Signature.fromRpc.ErrorType
1250
1250
  | Errors.GlobalErrorType
1251
1251
  }
@@ -1614,7 +1614,10 @@ export function toRpc<const envelope extends toRpc.Input>(
1614
1614
  assert(multisig)
1615
1615
  return {
1616
1616
  account: multisig.account,
1617
- config: MultisigConfig.toRpc(multisig.config),
1617
+ config: {
1618
+ ...multisig.config,
1619
+ version: Hex.toNumber(Hex.fromNumber(multisig.config.version)),
1620
+ },
1618
1621
  signatures: multisig.signatures.map((signature) => toRpc(signature)),
1619
1622
  } as never
1620
1623
  }
@@ -1643,7 +1646,8 @@ export declare namespace toRpc {
1643
1646
  type ErrorType =
1644
1647
  | assert.ErrorType
1645
1648
  | CoercionError
1646
- | MultisigConfig.toRpc.ErrorType
1649
+ | Hex.fromNumber.ErrorType
1650
+ | Hex.toNumber.ErrorType
1647
1651
  | Signature.toRpc.ErrorType
1648
1652
  | Errors.GlobalErrorType
1649
1653
  }
package/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** @internal */
2
- export const version = '0.14.40'
2
+ export const version = '0.14.41'