ox 1.0.0-beta.11 → 1.0.0-beta.13

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 (48) hide show
  1. package/dist/core/internal/rpcSchemas/eth.d.ts +16 -0
  2. package/dist/core/internal/rpcSchemas/eth.d.ts.map +1 -1
  3. package/dist/tempo/MultisigConfig.d.ts +37 -85
  4. package/dist/tempo/MultisigConfig.d.ts.map +1 -1
  5. package/dist/tempo/MultisigConfig.js +39 -83
  6. package/dist/tempo/MultisigConfig.js.map +1 -1
  7. package/dist/tempo/SignatureEnvelope.d.ts +32 -30
  8. package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
  9. package/dist/tempo/SignatureEnvelope.js +56 -51
  10. package/dist/tempo/SignatureEnvelope.js.map +1 -1
  11. package/dist/tempo/index.d.ts +2 -2
  12. package/dist/tempo/index.js +2 -2
  13. package/dist/zod/RpcSchema.d.ts +1 -0
  14. package/dist/zod/RpcSchema.d.ts.map +1 -1
  15. package/dist/zod/internal/rpcSchemas/Eth.d.ts +1 -0
  16. package/dist/zod/internal/rpcSchemas/Eth.d.ts.map +1 -1
  17. package/dist/zod/internal/rpcSchemas/Eth.js +5 -0
  18. package/dist/zod/internal/rpcSchemas/Eth.js.map +1 -1
  19. package/dist/zod/tempo/AuthorizationTempo.d.ts +0 -20
  20. package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
  21. package/dist/zod/tempo/KeyAuthorization.d.ts +0 -11
  22. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  23. package/dist/zod/tempo/RpcSchemaTempo.d.ts +0 -12
  24. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  25. package/dist/zod/tempo/SignatureEnvelope.d.ts +0 -6
  26. package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
  27. package/dist/zod/tempo/SignatureEnvelope.js +0 -2
  28. package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
  29. package/dist/zod/tempo/Transaction.d.ts +0 -24
  30. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  31. package/dist/zod/tempo/TransactionRequest.d.ts +0 -21
  32. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  33. package/dist/zod/tempo/TxEnvelopeTempo.d.ts +0 -9
  34. package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  35. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +0 -3
  36. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/src/core/internal/rpcSchemas/eth.ts +16 -0
  39. package/src/tempo/MultisigConfig.test.ts +54 -37
  40. package/src/tempo/MultisigConfig.ts +59 -134
  41. package/src/tempo/SignatureEnvelope.test.ts +118 -17
  42. package/src/tempo/SignatureEnvelope.ts +77 -72
  43. package/src/tempo/e2e.test.ts +221 -1
  44. package/src/tempo/index.ts +2 -2
  45. package/src/version.ts +1 -1
  46. package/src/zod/internal/rpcSchemas/Eth.ts +6 -0
  47. package/src/zod/tempo/SignatureEnvelope.ts +0 -2
  48. package/src/zod/tempo/_test/SignatureEnvelope.test.ts +0 -2
@@ -30,31 +30,51 @@ describe('from', () => {
30
30
  })
31
31
  })
32
32
 
33
- describe('genesisConfigId', () => {
33
+ describe('getAddress', () => {
34
34
  test('matches independent ground truth', () => {
35
- expect(MultisigConfig.toId(singleOwnerConfig)).toMatchInlineSnapshot(
36
- `"0xd1f20e1a5bfdd89488f57f68db5bd1aae9a51b510f4a042b2604b57a0b7b471d"`,
35
+ expect(MultisigConfig.getAddress(singleOwnerConfig)).toMatchInlineSnapshot(
36
+ `"0x8820d1497eeaf4f68e00b2cfc00a2f3b1dbb00da"`,
37
37
  )
38
38
  })
39
39
 
40
+ test('matches independent ground truth (salt + weights)', () => {
41
+ expect(
42
+ MultisigConfig.getAddress({
43
+ salt: `0x${'42'.repeat(32)}`,
44
+ threshold: 2,
45
+ owners: [
46
+ { owner: owner1, weight: 1 },
47
+ { owner: owner2, weight: 2 },
48
+ ],
49
+ }),
50
+ ).toMatchInlineSnapshot(`"0x0773e28146400643e42cb28f6659b74e7c0b451d"`)
51
+ })
52
+
40
53
  test('is stable across calls', () => {
41
- expect(MultisigConfig.toId(singleOwnerConfig)).toBe(
42
- MultisigConfig.toId(singleOwnerConfig),
54
+ expect(MultisigConfig.getAddress(singleOwnerConfig)).toBe(
55
+ MultisigConfig.getAddress(singleOwnerConfig),
43
56
  )
44
57
  })
45
58
 
46
59
  test('differs for a different salt', () => {
47
- expect(MultisigConfig.toId(singleOwnerConfig)).not.toBe(
48
- MultisigConfig.toId({
60
+ expect(MultisigConfig.getAddress(singleOwnerConfig)).not.toBe(
61
+ MultisigConfig.getAddress({
49
62
  ...singleOwnerConfig,
50
63
  salt: `0x${'42'.repeat(32)}`,
51
64
  }),
52
65
  )
53
66
  })
54
67
 
68
+ test('address is chain-independent', () => {
69
+ // Derivation does not include chain ID; identical config → identical address.
70
+ const a = MultisigConfig.getAddress(singleOwnerConfig)
71
+ const b = MultisigConfig.getAddress(MultisigConfig.from(singleOwnerConfig))
72
+ expect(a).toBe(b)
73
+ })
74
+
55
75
  test('throws on invalid config', () => {
56
76
  expect(() =>
57
- MultisigConfig.toId({
77
+ MultisigConfig.getAddress({
58
78
  threshold: 5,
59
79
  owners: singleOwnerConfig.owners,
60
80
  }),
@@ -62,50 +82,27 @@ describe('genesisConfigId', () => {
62
82
  })
63
83
  })
64
84
 
65
- describe('getAddress', () => {
66
- test('matches independent ground truth', () => {
67
- expect(MultisigConfig.getAddress(singleOwnerConfig)).toMatchInlineSnapshot(
68
- `"0x6ca655065b1de473d903eebd50e5cb4996e10468"`,
69
- )
70
- })
71
-
72
- test('derives from positional config or `{ genesisConfigId }` identically', () => {
73
- const genesisConfigId = MultisigConfig.toId(singleOwnerConfig)
74
- expect(MultisigConfig.getAddress({ genesisConfigId })).toBe(
75
- MultisigConfig.getAddress(singleOwnerConfig),
76
- )
77
- })
78
-
79
- test('config ID and address are chain-independent', () => {
80
- // Derivation does not include chain ID; identical config → identical id/address.
81
- const a = MultisigConfig.toId(singleOwnerConfig)
82
- const b = MultisigConfig.toId(MultisigConfig.from(singleOwnerConfig))
83
- expect(a).toBe(b)
84
- })
85
- })
86
-
87
85
  describe('getSignPayload', () => {
88
86
  test('matches independent ground truth', () => {
89
87
  expect(
90
88
  MultisigConfig.getSignPayload({
91
- payload: `0x${'42'.repeat(32)}`,
89
+ payload: `0x${'de'.repeat(32)}`,
92
90
  genesisConfig: singleOwnerConfig,
93
91
  }),
94
92
  ).toMatchInlineSnapshot(
95
- `"0xe3d66f6118b89a67c71c8137c46abf0c829056a46ee6a038a1b42c84529fc17e"`,
93
+ `"0x7df8cb9fef4fc2aeb271b617d1a4c6178b720ae1d7564f48a363069b7d77a079"`,
96
94
  )
97
95
  })
98
96
 
99
- test('behavior: `genesisConfig` and `{account, genesisConfigId}` produce identical digests', () => {
100
- const genesisConfigId = MultisigConfig.toId(singleOwnerConfig)
101
- const account = MultisigConfig.getAddress({ genesisConfigId })
97
+ test('behavior: `genesisConfig` and `{ account }` produce identical digests', () => {
98
+ const account = MultisigConfig.getAddress(singleOwnerConfig)
102
99
  const payload = `0x${'42'.repeat(32)}` as const
103
100
  expect(
104
101
  MultisigConfig.getSignPayload({
105
102
  payload,
106
103
  genesisConfig: singleOwnerConfig,
107
104
  }),
108
- ).toBe(MultisigConfig.getSignPayload({ payload, account, genesisConfigId }))
105
+ ).toBe(MultisigConfig.getSignPayload({ payload, account }))
109
106
  })
110
107
  })
111
108
 
@@ -152,8 +149,16 @@ describe('assert / validate', () => {
152
149
  expect(MultisigConfig.validate({ threshold: 1, owners: [] })).toBe(false)
153
150
  })
154
151
 
152
+ test('accepts 255 owners', () => {
153
+ const owners = Array.from({ length: 255 }, (_, i) => ({
154
+ owner: `0x${(i + 1).toString(16).padStart(40, '0')}` as `0x${string}`,
155
+ weight: 1,
156
+ }))
157
+ expect(MultisigConfig.validate({ threshold: 255, owners })).toBe(true)
158
+ })
159
+
155
160
  test('too many owners', () => {
156
- const owners = Array.from({ length: 11 }, (_, i) => ({
161
+ const owners = Array.from({ length: 256 }, (_, i) => ({
157
162
  owner: `0x${(i + 1).toString(16).padStart(40, '0')}` as `0x${string}`,
158
163
  weight: 1,
159
164
  }))
@@ -178,6 +183,18 @@ describe('assert / validate', () => {
178
183
  ).toBe(false)
179
184
  })
180
185
 
186
+ test('total weight exceeds u8 max', () => {
187
+ expect(
188
+ MultisigConfig.validate({
189
+ threshold: 255,
190
+ owners: [
191
+ { owner: owner1, weight: 128 },
192
+ { owner: owner2, weight: 128 },
193
+ ],
194
+ }),
195
+ ).toBe(false)
196
+ })
197
+
181
198
  test('zero owner weight', () => {
182
199
  expect(
183
200
  MultisigConfig.validate({
@@ -6,7 +6,13 @@ import * as Hex from '../core/Hex.js'
6
6
  import type { Compute, OneOf } from '../core/internal/types.js'
7
7
 
8
8
  /** Maximum number of owners allowed in a native multisig config. */
9
- export const maxOwners = 10
9
+ export const maxOwners = 255
10
+
11
+ /**
12
+ * Maximum number of native multisig signatures in one nested authorization
13
+ * path, including the top-level transaction signature.
14
+ */
15
+ export const maxNestingDepth = 3
10
16
 
11
17
  /** Maximum encoded byte length for one primitive owner approval. */
12
18
  export const maxOwnerSignatureBytes = 2049
@@ -20,20 +26,17 @@ export const zeroSalt = `0x${'00'.repeat(32)}` as const
20
26
  /** Domain prefix for the native multisig account address derivation. */
21
27
  const accountDomain = 'tempo:multisig:account'
22
28
 
23
- /** Domain prefix for the native multisig config ID derivation. */
24
- const configDomain = 'tempo:multisig:config'
25
-
26
29
  /** Domain prefix for native multisig owner approvals. */
27
30
  const signatureDomain = 'tempo:multisig:signature'
28
31
 
29
32
  /**
30
- * Native multisig configuration. Determines the permanent config ID and the
31
- * stable multisig account address.
33
+ * Native multisig configuration. Determines the stable multisig account
34
+ * address.
32
35
  */
33
36
  export type Config<numberType = number> = Compute<{
34
37
  /**
35
- * Caller-chosen 32-byte salt mixed into the permanent config ID. Defaults to
36
- * the zero salt (`MultisigConfig.zeroSalt`) when omitted.
38
+ * Caller-chosen 32-byte salt mixed into the derived account address.
39
+ * Defaults to the zero salt (`MultisigConfig.zeroSalt`) when omitted.
37
40
  */
38
41
  salt?: Hex.Hex | undefined
39
42
  /** Minimum total owner weight required to authorize a transaction. */
@@ -44,7 +47,7 @@ export type Config<numberType = number> = Compute<{
44
47
 
45
48
  /** Native multisig owner entry. */
46
49
  export type Owner<numberType = number> = {
47
- /** Owner address (recovered from the owner's primitive signature). */
50
+ /** Owner address (recovered from the owner's approval). */
48
51
  owner: Address.Address
49
52
  /** Nonzero owner weight. */
50
53
  weight: numberType
@@ -60,9 +63,9 @@ export type Tuple = readonly [
60
63
  /**
61
64
  * Asserts that a native multisig {@link ox#MultisigConfig.Config} is valid.
62
65
  *
63
- * Mirrors the Tempo `validate_multisig_config` rules: owners non-empty and
66
+ * Mirrors the Tempo `InitMultisig::validate` rules: owners non-empty and
64
67
  * `<= maxOwners`, strictly ascending unique nonzero owner addresses, nonzero
65
- * owner weights, `threshold >= 1`, total weight `<= u32::MAX`, and
68
+ * owner weights, `threshold >= 1`, total weight `<= 255` (u8 max), and
66
69
  * `threshold <= total weight`.
67
70
  *
68
71
  * @example
@@ -112,9 +115,9 @@ export function assert<numberType = number>(config: Config<numberType>): void {
112
115
  totalWeight += Number(owner.weight)
113
116
  }
114
117
 
115
- if (totalWeight > 0xffffffff)
118
+ if (totalWeight > 0xff)
116
119
  throw new InvalidConfigError({
117
- reason: 'total owner weight exceeds u32 max',
120
+ reason: 'total owner weight exceeds u8 max',
118
121
  })
119
122
  if (Number(threshold) > totalWeight)
120
123
  throw new InvalidConfigError({
@@ -130,7 +133,7 @@ export declare namespace assert {
130
133
  * Normalizes a native multisig {@link ox#MultisigConfig.Config}.
131
134
  *
132
135
  * Sorts owners into strictly ascending `owner` address order (the canonical
133
- * form required for config ID derivation) and asserts the config is valid.
136
+ * form required for account derivation) and asserts the config is valid.
134
137
  *
135
138
  * @example
136
139
  * ```ts twoslash
@@ -206,7 +209,11 @@ export function fromTuple(tuple: Tuple): Config {
206
209
  /**
207
210
  * Derives the stable native multisig account address.
208
211
  *
209
- * `keccak256("tempo:multisig:account" || config_id)[12:32]`.
212
+ * Preimage (fixed-width big-endian, **not** RLP):
213
+ * `keccak256("tempo:multisig:account" || salt || u8(threshold) || u8(owners.length) || (owner || u8(weight)) for each owner)[12:32]`.
214
+ *
215
+ * The address is derived once from the initial (bootstrap) config and never
216
+ * changes — config updates do not affect it.
210
217
  *
211
218
  * @example
212
219
  * ```ts twoslash
@@ -225,50 +232,37 @@ export function fromTuple(tuple: Tuple): Config {
225
232
  * const address = MultisigConfig.getAddress(genesisConfig)
226
233
  * ```
227
234
  *
228
- * @example
229
- * ### From an genesis config ID
230
- *
231
- * If you already have the permanent `genesisConfigId`, pass it directly:
232
- *
233
- * ```ts twoslash
234
- * import { MultisigConfig } from 'ox/tempo'
235
- *
236
- * const genesisConfigId = `0x${'00'.repeat(32)}` as const
237
- *
238
- * const address = MultisigConfig.getAddress({
239
- * genesisConfigId
240
- * })
241
- * ```
242
- *
243
- * @param value - The genesis config (positional) or `{ genesisConfigId }`.
235
+ * @param config - The initial (bootstrap) multisig config.
244
236
  * @returns The multisig account address.
245
237
  */
246
- export function getAddress(value: getAddress.Value): Address.Address {
247
- const id =
248
- typeof value === 'object' && 'genesisConfigId' in value
249
- ? value.genesisConfigId
250
- : toId(value)
251
- const hash = Hash.keccak256(Hex.concat(Hex.fromString(accountDomain), id))
252
- return Address.from(Hex.slice(hash, 12, 32))
238
+ export function getAddress(config: Config): Address.Address {
239
+ assert(config)
240
+ const hash = Hash.keccak256(
241
+ Hex.concat(
242
+ Hex.fromString(accountDomain),
243
+ Hex.padLeft(config.salt ?? zeroSalt, 32),
244
+ Hex.fromNumber(config.threshold, { size: 1 }),
245
+ Hex.fromNumber(config.owners.length, { size: 1 }),
246
+ ...config.owners.flatMap((owner) => [
247
+ owner.owner,
248
+ Hex.fromNumber(owner.weight, { size: 1 }),
249
+ ]),
250
+ ),
251
+ )
252
+ const account = Address.from(Hex.slice(hash, 12, 32))
253
+ if (Hex.toBigInt(account) === 0n)
254
+ throw new InvalidConfigError({ reason: 'derived account cannot be zero' })
255
+ return account
253
256
  }
254
257
 
255
258
  export declare namespace getAddress {
256
- type Value =
257
- | Config
258
- | {
259
- /**
260
- * The permanent genesis config ID (`MultisigConfig.toId(genesisConfig)`).
261
- * Config updates never change this value, so it identifies the
262
- * account permanently.
263
- */
264
- genesisConfigId: Hex.Hex
265
- }
266
-
267
259
  type ErrorType =
268
- | toId.ErrorType
260
+ | assert.ErrorType
269
261
  | Address.from.ErrorType
270
262
  | Hash.keccak256.ErrorType
271
263
  | Hex.concat.ErrorType
264
+ | Hex.fromNumber.ErrorType
265
+ | Hex.fromString.ErrorType
272
266
  | Hex.slice.ErrorType
273
267
  | Errors.GlobalErrorType
274
268
  }
@@ -276,14 +270,16 @@ export declare namespace getAddress {
276
270
  /**
277
271
  * Computes the digest a native multisig owner approves (signs).
278
272
  *
279
- * `keccak256("tempo:multisig:signature" || inner_digest || account || config_id)`,
273
+ * `keccak256("tempo:multisig:signature" || inner_digest || account)`,
280
274
  * where `inner_digest` is the transaction sign payload
281
275
  * ({@link ox#TxEnvelopeTempo.(getSignPayload:function)}).
282
276
  *
283
- * The digest is always keyed on the permanent `account`/`genesisConfigId`
284
- * derived from the genesis (bootstrap) config — config updates never change
285
- * these values, so the genesis config is the correct input even for
286
- * post-update transactions.
277
+ * The digest is keyed on the permanent `account` derived from the genesis
278
+ * (bootstrap) config — config updates never change it, so the genesis config
279
+ * is the correct input even for post-update transactions.
280
+ *
281
+ * For a nested multisig owner approval, the parent digest becomes the nested
282
+ * approval's `payload`, with the nested multisig `account`.
287
283
  *
288
284
  * @example
289
285
  * ```ts twoslash
@@ -311,10 +307,10 @@ export declare namespace getAddress {
311
307
  * ```
312
308
  *
313
309
  * @example
314
- * ### From `account` + `genesisConfigId`
310
+ * ### From `account`
315
311
  *
316
- * If you already have the permanent `account` and `genesisConfigId` (for
317
- * example, recovered from a stored envelope), pass them directly:
312
+ * If you already have the permanent `account` (for example, recovered from a
313
+ * stored envelope), pass it directly:
318
314
  *
319
315
  * ```ts twoslash
320
316
  * import { MultisigConfig, TxEnvelopeTempo } from 'ox/tempo'
@@ -328,7 +324,6 @@ export declare namespace getAddress {
328
324
  * }
329
325
  * ]
330
326
  * })
331
- * const genesisConfigId = MultisigConfig.toId(genesisConfig)
332
327
  * const account = MultisigConfig.getAddress(genesisConfig)
333
328
  *
334
329
  * const envelope = TxEnvelopeTempo.from({
@@ -338,8 +333,7 @@ export declare namespace getAddress {
338
333
  *
339
334
  * const digest = MultisigConfig.getSignPayload({
340
335
  * payload: TxEnvelopeTempo.getSignPayload(envelope),
341
- * account,
342
- * genesisConfigId
336
+ * account
343
337
  * })
344
338
  * ```
345
339
  *
@@ -352,17 +346,8 @@ export function getSignPayload(value: getSignPayload.Value): Hex.Hex {
352
346
  'account' in value && value.account
353
347
  ? value.account
354
348
  : getAddress((value as { genesisConfig: Config }).genesisConfig)
355
- const genesisConfigId =
356
- 'genesisConfigId' in value && value.genesisConfigId
357
- ? value.genesisConfigId
358
- : toId((value as { genesisConfig: Config }).genesisConfig)
359
349
  return Hash.keccak256(
360
- Hex.concat(
361
- Hex.fromString(signatureDomain),
362
- Hex.from(payload),
363
- account,
364
- genesisConfigId,
365
- ),
350
+ Hex.concat(Hex.fromString(signatureDomain), Hex.from(payload), account),
366
351
  )
367
352
  }
368
353
 
@@ -374,16 +359,13 @@ export declare namespace getSignPayload {
374
359
  | {
375
360
  /** The native multisig account address. */
376
361
  account: Address.Address
377
- /** The permanent config ID. */
378
- genesisConfigId: Hex.Hex
379
362
  }
380
363
  | {
381
364
  /**
382
365
  * The initial multisig config (the bootstrap config that derived the
383
- * permanent `account` and `genesisConfigId`). Used to derive both values
384
- * automatically. Config updates never change `account`/`genesisConfigId`,
385
- * so the genesis config is also the correct input for post-update
386
- * transactions.
366
+ * permanent `account`). Used to derive the account automatically.
367
+ * Config updates never change `account`, so the genesis config is
368
+ * also the correct input for post-update transactions.
387
369
  */
388
370
  genesisConfig: Config
389
371
  }
@@ -391,69 +373,12 @@ export declare namespace getSignPayload {
391
373
 
392
374
  type ErrorType =
393
375
  | getAddress.ErrorType
394
- | toId.ErrorType
395
376
  | Hash.keccak256.ErrorType
396
377
  | Hex.concat.ErrorType
397
378
  | Hex.from.ErrorType
398
379
  | Errors.GlobalErrorType
399
380
  }
400
381
 
401
- /**
402
- * Derives the permanent config ID for a native multisig
403
- * {@link ox#MultisigConfig.Config}.
404
- *
405
- * Preimage (fixed-width big-endian, **not** RLP):
406
- * `keccak256("tempo:multisig:config" || salt || be_u32(threshold) || be_u32(owners.length) || (owner || be_u32(weight)) for each owner)`.
407
- *
408
- * @example
409
- * ```ts twoslash
410
- * import { MultisigConfig } from 'ox/tempo'
411
- *
412
- * const config = MultisigConfig.from({
413
- * threshold: 1,
414
- * owners: [
415
- * {
416
- * owner: '0x1111111111111111111111111111111111111111',
417
- * weight: 1
418
- * }
419
- * ]
420
- * })
421
- *
422
- * const genesisConfigId = MultisigConfig.toId(config)
423
- * ```
424
- *
425
- * @param config - The multisig config.
426
- * @returns The 32-byte config ID.
427
- */
428
- export function toId(config: Config): Hex.Hex {
429
- assert(config)
430
- const id = Hash.keccak256(
431
- Hex.concat(
432
- Hex.fromString(configDomain),
433
- Hex.padLeft(config.salt ?? zeroSalt, 32),
434
- Hex.fromNumber(config.threshold, { size: 4 }),
435
- Hex.fromNumber(config.owners.length, { size: 4 }),
436
- ...config.owners.flatMap((owner) => [
437
- owner.owner,
438
- Hex.fromNumber(owner.weight, { size: 4 }),
439
- ]),
440
- ),
441
- )
442
- if (Hex.toBigInt(id) === 0n)
443
- throw new InvalidConfigError({ reason: 'config ID cannot be zero' })
444
- return id
445
- }
446
-
447
- export declare namespace toId {
448
- type ErrorType =
449
- | assert.ErrorType
450
- | Hash.keccak256.ErrorType
451
- | Hex.concat.ErrorType
452
- | Hex.fromNumber.ErrorType
453
- | Hex.fromString.ErrorType
454
- | Errors.GlobalErrorType
455
- }
456
-
457
382
  /**
458
383
  * Converts a {@link ox#MultisigConfig.Config} to its RLP tuple form (carried
459
384
  * by the multisig signature `init`).