ox 0.14.55 → 0.14.57
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.
- package/CHANGELOG.md +48 -0
- package/_cjs/tempo/{MultisigConfig.js → AccountConfig.js} +32 -9
- package/_cjs/tempo/AccountConfig.js.map +1 -0
- package/_cjs/tempo/{MultisigOperation.js → AccountOperation.js} +29 -29
- package/_cjs/tempo/AccountOperation.js.map +1 -0
- package/_cjs/tempo/{MultisigSimulation.js → AccountSimulation.js} +22 -13
- package/_cjs/tempo/AccountSimulation.js.map +1 -0
- package/_cjs/tempo/KeyAuthorization.js +10 -18
- package/_cjs/tempo/KeyAuthorization.js.map +1 -1
- package/_cjs/tempo/SignatureEnvelope.js +64 -64
- package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
- package/_cjs/tempo/TransactionRequest.js +15 -10
- package/_cjs/tempo/TransactionRequest.js.map +1 -1
- package/_cjs/tempo/index.js +4 -4
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/tempo/{MultisigConfig.js → AccountConfig.js} +161 -64
- package/_esm/tempo/AccountConfig.js.map +1 -0
- package/_esm/tempo/{MultisigOperation.js → AccountOperation.js} +64 -64
- package/_esm/tempo/AccountOperation.js.map +1 -0
- package/_esm/tempo/{MultisigSimulation.js → AccountSimulation.js} +35 -25
- package/_esm/tempo/AccountSimulation.js.map +1 -0
- package/_esm/tempo/KeyAuthorization.js +16 -19
- package/_esm/tempo/KeyAuthorization.js.map +1 -1
- package/_esm/tempo/SignatureEnvelope.js +71 -71
- package/_esm/tempo/SignatureEnvelope.js.map +1 -1
- package/_esm/tempo/TransactionRequest.js +15 -10
- package/_esm/tempo/TransactionRequest.js.map +1 -1
- package/_esm/tempo/index.js +50 -48
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/tempo/{MultisigConfig.d.ts → AccountConfig.d.ts} +156 -66
- package/_types/tempo/AccountConfig.d.ts.map +1 -0
- package/_types/tempo/{MultisigOperation.d.ts → AccountOperation.d.ts} +62 -62
- package/_types/tempo/AccountOperation.d.ts.map +1 -0
- package/_types/tempo/{MultisigSimulation.d.ts → AccountSimulation.d.ts} +25 -21
- package/_types/tempo/AccountSimulation.d.ts.map +1 -0
- package/_types/tempo/KeyAuthorization.d.ts +28 -23
- package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
- package/_types/tempo/RpcSchemaTempo.d.ts +13 -13
- package/_types/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/_types/tempo/SignatureEnvelope.d.ts +36 -33
- package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/_types/tempo/TransactionRequest.d.ts +11 -9
- package/_types/tempo/TransactionRequest.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +50 -48
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/package.json +31 -31
- package/tempo/AccountConfig/package.json +6 -0
- package/tempo/AccountConfig.test-d/package.json +6 -0
- package/tempo/AccountConfig.test-d.ts +72 -0
- package/tempo/AccountConfig.test.ts +642 -0
- package/tempo/{MultisigConfig.ts → AccountConfig.ts} +212 -75
- package/tempo/AccountOperation/package.json +6 -0
- package/tempo/AccountOperation.test-d/package.json +6 -0
- package/tempo/AccountOperation.test-d.ts +71 -0
- package/tempo/{MultisigOperation.test.ts → AccountOperation.test.ts} +129 -129
- package/tempo/{MultisigOperation.ts → AccountOperation.ts} +95 -97
- package/tempo/AccountSimulation/package.json +6 -0
- package/tempo/AccountSimulation.test-d/package.json +6 -0
- package/tempo/{MultisigSimulation.test-d.ts → AccountSimulation.test-d.ts} +7 -9
- package/tempo/{MultisigSimulation.test.ts → AccountSimulation.test.ts} +73 -29
- package/tempo/{MultisigSimulation.ts → AccountSimulation.ts} +47 -35
- package/tempo/KeyAuthorization.test-d.ts +19 -29
- package/tempo/KeyAuthorization.test.ts +151 -74
- package/tempo/KeyAuthorization.ts +40 -61
- package/tempo/RpcSchemaTempo.test-d.ts +20 -20
- package/tempo/RpcSchemaTempo.ts +13 -13
- package/tempo/SignatureEnvelope.test-d.ts +7 -7
- package/tempo/SignatureEnvelope.test.ts +34 -34
- package/tempo/SignatureEnvelope.ts +107 -103
- package/tempo/Transaction.test.ts +4 -4
- package/tempo/TransactionRequest.test-d.ts +17 -8
- package/tempo/TransactionRequest.test.ts +31 -21
- package/tempo/TransactionRequest.ts +29 -20
- package/tempo/{multisig.e2e.test.ts → configurableAccounts.e2e.test.ts} +16 -16
- package/tempo/index.ts +50 -48
- package/version.ts +1 -1
- package/_cjs/tempo/MultisigConfig.js.map +0 -1
- package/_cjs/tempo/MultisigOperation.js.map +0 -1
- package/_cjs/tempo/MultisigSimulation.js.map +0 -1
- package/_esm/tempo/MultisigConfig.js.map +0 -1
- package/_esm/tempo/MultisigOperation.js.map +0 -1
- package/_esm/tempo/MultisigSimulation.js.map +0 -1
- package/_types/tempo/MultisigConfig.d.ts.map +0 -1
- package/_types/tempo/MultisigOperation.d.ts.map +0 -1
- package/_types/tempo/MultisigSimulation.d.ts.map +0 -1
- package/tempo/MultisigConfig/package.json +0 -6
- package/tempo/MultisigConfig.test-d/package.json +0 -6
- package/tempo/MultisigConfig.test-d.ts +0 -52
- package/tempo/MultisigConfig.test.ts +0 -391
- package/tempo/MultisigOperation/package.json +0 -6
- package/tempo/MultisigOperation.test-d/package.json +0 -6
- package/tempo/MultisigOperation.test-d.ts +0 -71
- package/tempo/MultisigSimulation/package.json +0 -6
- package/tempo/MultisigSimulation.test-d/package.json +0 -6
|
@@ -9,39 +9,52 @@ import type { Compute } from '../core/internal/types.js'
|
|
|
9
9
|
/** Maximum encoded byte length for one primitive owner approval. */
|
|
10
10
|
export const maxOwnerSignatureBytes = 2049
|
|
11
11
|
|
|
12
|
-
/** Maximum number of owners allowed in
|
|
12
|
+
/** Maximum number of owners allowed in an account config. */
|
|
13
13
|
export const maxOwners = 48
|
|
14
14
|
|
|
15
|
-
/** Maximum number of owner approvals in a
|
|
15
|
+
/** Maximum number of owner approvals in a configurable account signature. */
|
|
16
16
|
export const maxSignatures = 8
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Maximum threshold accepted by an account config.
|
|
20
|
+
*
|
|
21
|
+
* The threshold must also be reachable by at most {@link ox#AccountConfig.maxSignatures}
|
|
22
|
+
* owner approvals.
|
|
23
|
+
*/
|
|
24
|
+
export const maxThreshold = 0xff
|
|
20
25
|
|
|
21
|
-
/** Maximum version accepted by
|
|
26
|
+
/** Maximum version accepted by an account config. */
|
|
22
27
|
export const maxVersion = 2n ** 64n - 1n
|
|
23
28
|
|
|
24
|
-
/** Tempo signature type byte for
|
|
29
|
+
/** Tempo signature type byte for configurable account signatures. */
|
|
25
30
|
export const signatureTypeByte = '0x05' as const
|
|
26
31
|
|
|
27
32
|
/** Zero 32-byte salt (the default when no salt is provided). */
|
|
28
33
|
export const zeroSalt = `0x${'00'.repeat(32)}` as const
|
|
29
34
|
|
|
30
|
-
/** Domain prefix for the
|
|
31
|
-
const accountDomain = 'tempo:
|
|
35
|
+
/** Domain prefix for the configurable account address derivation. */
|
|
36
|
+
const accountDomain = 'tempo:configurable-account:account'
|
|
32
37
|
|
|
33
|
-
/** Domain prefix for
|
|
34
|
-
const configDomain = 'tempo:
|
|
38
|
+
/** Domain prefix for account configuration commitments. */
|
|
39
|
+
const configDomain = 'tempo:configurable-account:config'
|
|
35
40
|
|
|
36
|
-
/**
|
|
37
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Keccak-256 of the account proxy creation code.
|
|
43
|
+
*
|
|
44
|
+
* Placeholder until [TIP-1110](https://tips.sh/1110) fixes the canonical
|
|
45
|
+
* account proxy, which will change every derived address.
|
|
46
|
+
*/
|
|
47
|
+
const accountProxyInitCodeHash =
|
|
38
48
|
'0x583cc63a2e37f645b43eac911b1a6d6de08b83abdc308c61364edda8cfc3bd37'
|
|
39
49
|
|
|
40
|
-
/** Domain prefix for
|
|
41
|
-
const signatureDomain = 'tempo:
|
|
50
|
+
/** Domain prefix for configurable account owner approvals. */
|
|
51
|
+
const signatureDomain = 'tempo:configurable-account:signature'
|
|
52
|
+
|
|
53
|
+
/** Domain prefix for the salt of an account migrated in place. */
|
|
54
|
+
const upgradeDomain = 'tempo:configurable-account:upgrade'
|
|
42
55
|
|
|
43
56
|
/**
|
|
44
|
-
* Complete
|
|
57
|
+
* Complete account configuration witness.
|
|
45
58
|
*/
|
|
46
59
|
export type Config<bigintType = bigint, numberType = number> = Compute<{
|
|
47
60
|
/** Weighted owner list, strictly ascending by owner address. */
|
|
@@ -54,7 +67,7 @@ export type Config<bigintType = bigint, numberType = number> = Compute<{
|
|
|
54
67
|
version: bigintType
|
|
55
68
|
}>
|
|
56
69
|
|
|
57
|
-
/** Input accepted when constructing
|
|
70
|
+
/** Input accepted when constructing an account configuration. */
|
|
58
71
|
export type Input<
|
|
59
72
|
versionType extends bigint | number = bigint | number,
|
|
60
73
|
numberType = number,
|
|
@@ -63,7 +76,7 @@ export type Input<
|
|
|
63
76
|
owners: readonly Owner<numberType>[]
|
|
64
77
|
/**
|
|
65
78
|
* Caller-chosen 32-byte salt mixed into the derived account address.
|
|
66
|
-
* Defaults to the zero salt (`
|
|
79
|
+
* Defaults to the zero salt (`AccountConfig.zeroSalt`) when omitted.
|
|
67
80
|
*/
|
|
68
81
|
salt?: Hex.Hex | undefined
|
|
69
82
|
/** Minimum total owner weight required to authorize a transaction. */
|
|
@@ -72,7 +85,7 @@ export type Input<
|
|
|
72
85
|
version?: versionType | undefined
|
|
73
86
|
}>
|
|
74
87
|
|
|
75
|
-
/**
|
|
88
|
+
/** Account config owner entry. */
|
|
76
89
|
export type Owner<numberType = number> = {
|
|
77
90
|
/** Owner address (recovered from the owner's approval). */
|
|
78
91
|
owner: Address.Address
|
|
@@ -80,10 +93,10 @@ export type Owner<numberType = number> = {
|
|
|
80
93
|
weight: numberType
|
|
81
94
|
}
|
|
82
95
|
|
|
83
|
-
/** JSON-RPC representation of
|
|
96
|
+
/** JSON-RPC representation of an account configuration. */
|
|
84
97
|
export type Rpc = Config<Hex.Hex, number>
|
|
85
98
|
|
|
86
|
-
/** RLP tuple representation of a {@link ox#
|
|
99
|
+
/** RLP tuple representation of a {@link ox#AccountConfig.Config}. */
|
|
87
100
|
export type Tuple = readonly [
|
|
88
101
|
salt: Hex.Hex,
|
|
89
102
|
version: Hex.Hex,
|
|
@@ -92,7 +105,7 @@ export type Tuple = readonly [
|
|
|
92
105
|
]
|
|
93
106
|
|
|
94
107
|
/**
|
|
95
|
-
* Asserts that
|
|
108
|
+
* Asserts that an {@link ox#AccountConfig.Config} is valid.
|
|
96
109
|
*
|
|
97
110
|
* Mirrors the Tempo configuration rules: owners non-empty and
|
|
98
111
|
* `<= maxOwners`, strictly ascending unique nonzero owner addresses, nonzero
|
|
@@ -102,9 +115,9 @@ export type Tuple = readonly [
|
|
|
102
115
|
*
|
|
103
116
|
* @example
|
|
104
117
|
* ```ts twoslash
|
|
105
|
-
* import {
|
|
118
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
106
119
|
*
|
|
107
|
-
*
|
|
120
|
+
* AccountConfig.assert({
|
|
108
121
|
* threshold: 1,
|
|
109
122
|
* owners: [
|
|
110
123
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
@@ -112,7 +125,7 @@ export type Tuple = readonly [
|
|
|
112
125
|
* })
|
|
113
126
|
* ```
|
|
114
127
|
*
|
|
115
|
-
* @param config - The
|
|
128
|
+
* @param config - The account config.
|
|
116
129
|
*/
|
|
117
130
|
export function assert<
|
|
118
131
|
versionType extends bigint | number = bigint | number,
|
|
@@ -183,16 +196,16 @@ export declare namespace assert {
|
|
|
183
196
|
}
|
|
184
197
|
|
|
185
198
|
/**
|
|
186
|
-
* Normalizes
|
|
199
|
+
* Normalizes an {@link ox#AccountConfig.Config}.
|
|
187
200
|
*
|
|
188
201
|
* Sorts owners into strictly ascending `owner` address order (the canonical
|
|
189
202
|
* form required for account derivation) and asserts the config is valid.
|
|
190
203
|
*
|
|
191
204
|
* @example
|
|
192
205
|
* ```ts twoslash
|
|
193
|
-
* import {
|
|
206
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
194
207
|
*
|
|
195
|
-
* const config =
|
|
208
|
+
* const config = AccountConfig.from({
|
|
196
209
|
* owners: [
|
|
197
210
|
* { owner: '0x2222222222222222222222222222222222222222', weight: 1 },
|
|
198
211
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
@@ -202,8 +215,8 @@ export declare namespace assert {
|
|
|
202
215
|
* // owners are now sorted ascending by address
|
|
203
216
|
* ```
|
|
204
217
|
*
|
|
205
|
-
* @param config - The
|
|
206
|
-
* @returns The normalized
|
|
218
|
+
* @param config - The account config.
|
|
219
|
+
* @returns The normalized account config.
|
|
207
220
|
*/
|
|
208
221
|
export function from<numberType = number>(
|
|
209
222
|
config: Input<0 | 0n, numberType> & { version?: 0 | 0n | undefined },
|
|
@@ -237,13 +250,13 @@ export function from<numberType = number>(
|
|
|
237
250
|
}
|
|
238
251
|
|
|
239
252
|
/**
|
|
240
|
-
* Converts a JSON-RPC
|
|
253
|
+
* Converts a JSON-RPC account configuration to its domain representation.
|
|
241
254
|
*
|
|
242
255
|
* @example
|
|
243
256
|
* ```ts twoslash
|
|
244
|
-
* import {
|
|
257
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
245
258
|
*
|
|
246
|
-
* const config =
|
|
259
|
+
* const config = AccountConfig.fromRpc({
|
|
247
260
|
* owners: [
|
|
248
261
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
249
262
|
* ],
|
|
@@ -253,8 +266,8 @@ export function from<numberType = number>(
|
|
|
253
266
|
* })
|
|
254
267
|
* ```
|
|
255
268
|
*
|
|
256
|
-
* @param config - The JSON-RPC
|
|
257
|
-
* @returns The normalized
|
|
269
|
+
* @param config - The JSON-RPC account configuration.
|
|
270
|
+
* @returns The normalized account configuration.
|
|
258
271
|
*/
|
|
259
272
|
export function fromRpc(config: Rpc): Config {
|
|
260
273
|
return from({
|
|
@@ -271,14 +284,14 @@ export declare namespace fromRpc {
|
|
|
271
284
|
}
|
|
272
285
|
|
|
273
286
|
/**
|
|
274
|
-
* Converts an RLP {@link ox#
|
|
275
|
-
* {@link ox#
|
|
287
|
+
* Converts an RLP {@link ox#AccountConfig.Tuple} back to a
|
|
288
|
+
* {@link ox#AccountConfig.Config}.
|
|
276
289
|
*
|
|
277
290
|
* @example
|
|
278
291
|
* ```ts twoslash
|
|
279
|
-
* import {
|
|
292
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
280
293
|
*
|
|
281
|
-
* const config =
|
|
294
|
+
* const config = AccountConfig.fromTuple([
|
|
282
295
|
* `0x${'00'.repeat(32)}`,
|
|
283
296
|
* '0x',
|
|
284
297
|
* '0x01',
|
|
@@ -287,7 +300,7 @@ export declare namespace fromRpc {
|
|
|
287
300
|
* ```
|
|
288
301
|
*
|
|
289
302
|
* @param tuple - The RLP tuple.
|
|
290
|
-
* @returns The
|
|
303
|
+
* @returns The account config.
|
|
291
304
|
*/
|
|
292
305
|
export function fromTuple(tuple: Tuple): Config {
|
|
293
306
|
const [salt, version, threshold, owners] = tuple
|
|
@@ -331,34 +344,97 @@ export function fromTuple(tuple: Tuple): Config {
|
|
|
331
344
|
}
|
|
332
345
|
|
|
333
346
|
/**
|
|
334
|
-
* Derives the
|
|
347
|
+
* Derives the configuration an existing account installs when it migrates in
|
|
348
|
+
* place with the `upgradeAccount` precompile call
|
|
349
|
+
* ([TIP-1113](https://tips.sh/1113)).
|
|
350
|
+
*
|
|
351
|
+
* The account keeps its address. Its salt is
|
|
352
|
+
* `keccak256("tempo:configurable-account:upgrade" || account)` and its version
|
|
353
|
+
* is `1n`. Owners are sorted into canonical order and the config is validated.
|
|
354
|
+
* The account itself may be listed as an owner.
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```ts twoslash
|
|
358
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
359
|
+
*
|
|
360
|
+
* const config = AccountConfig.fromUpgrade(
|
|
361
|
+
* '0x3333333333333333333333333333333333333333',
|
|
362
|
+
* {
|
|
363
|
+
* owners: [
|
|
364
|
+
* {
|
|
365
|
+
* owner: '0x1111111111111111111111111111111111111111',
|
|
366
|
+
* weight: 1
|
|
367
|
+
* }
|
|
368
|
+
* ],
|
|
369
|
+
* threshold: 1
|
|
370
|
+
* }
|
|
371
|
+
* )
|
|
372
|
+
* // config.version === 1n
|
|
373
|
+
* ```
|
|
374
|
+
*
|
|
375
|
+
* @param account - The account migrating in place.
|
|
376
|
+
* @param options - The owners and threshold to install.
|
|
377
|
+
* @returns The installed account config.
|
|
378
|
+
*/
|
|
379
|
+
export function fromUpgrade<numberType = number>(
|
|
380
|
+
account: Address.Address,
|
|
381
|
+
options: fromUpgrade.Options<numberType>,
|
|
382
|
+
): Config<1n, numberType> {
|
|
383
|
+
Address.assert(account)
|
|
384
|
+
return from({
|
|
385
|
+
owners: options.owners,
|
|
386
|
+
salt: Hash.keccak256(Hex.concat(Hex.fromString(upgradeDomain), account)),
|
|
387
|
+
threshold: options.threshold,
|
|
388
|
+
version: 1n,
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export declare namespace fromUpgrade {
|
|
393
|
+
type Options<numberType = number> = {
|
|
394
|
+
/** Weighted owners to install. Sorted into canonical order. */
|
|
395
|
+
owners: readonly Owner<numberType>[]
|
|
396
|
+
/** Minimum total owner weight required for authorization. */
|
|
397
|
+
threshold: numberType
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
type ErrorType =
|
|
401
|
+
| Address.assert.ErrorType
|
|
402
|
+
| assert.ErrorType
|
|
403
|
+
| Hash.keccak256.ErrorType
|
|
404
|
+
| Hex.concat.ErrorType
|
|
405
|
+
| Hex.fromString.ErrorType
|
|
406
|
+
| Errors.GlobalErrorType
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Derives the stable configurable account address.
|
|
335
411
|
*
|
|
336
412
|
* The initial config is hashed into a CREATE2 salt using fixed-width
|
|
337
413
|
* big-endian fields, not RLP. The account uses the chain-configured recovery
|
|
338
|
-
* factory and
|
|
414
|
+
* factory and account proxy init-code hash.
|
|
339
415
|
*
|
|
340
416
|
* The address is derived once from the initial version-0 config. Config
|
|
341
417
|
* updates do not change it.
|
|
342
418
|
*
|
|
343
419
|
* @example
|
|
344
420
|
* ```ts twoslash
|
|
345
|
-
* import {
|
|
421
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
346
422
|
*
|
|
347
|
-
* const initialConfig =
|
|
423
|
+
* const initialConfig = AccountConfig.from({
|
|
348
424
|
* owners: [
|
|
349
425
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
350
426
|
* ],
|
|
351
427
|
* threshold: 1,
|
|
352
428
|
* })
|
|
353
429
|
*
|
|
354
|
-
* const address =
|
|
430
|
+
* const address = AccountConfig.getAddress(initialConfig, {
|
|
355
431
|
* factory: '0x7171717171717171717171717171717171717171'
|
|
356
432
|
* })
|
|
357
433
|
* ```
|
|
358
434
|
*
|
|
359
|
-
* @param config - The initial
|
|
435
|
+
* @param config - The initial account config.
|
|
360
436
|
* @param options - The recovery factory configured by the chain.
|
|
361
|
-
* @returns The
|
|
437
|
+
* @returns The configurable account address.
|
|
362
438
|
*/
|
|
363
439
|
export function getAddress(
|
|
364
440
|
config: Input,
|
|
@@ -383,7 +459,7 @@ export function getAddress(
|
|
|
383
459
|
),
|
|
384
460
|
)
|
|
385
461
|
const account = ContractAddress.fromCreate2({
|
|
386
|
-
bytecodeHash:
|
|
462
|
+
bytecodeHash: accountProxyInitCodeHash,
|
|
387
463
|
from: options.factory,
|
|
388
464
|
salt: accountSalt,
|
|
389
465
|
})
|
|
@@ -413,16 +489,16 @@ export declare namespace getAddress {
|
|
|
413
489
|
}
|
|
414
490
|
|
|
415
491
|
/**
|
|
416
|
-
* Computes the commitment for
|
|
492
|
+
* Computes the commitment for an account configuration.
|
|
417
493
|
*
|
|
418
494
|
* The commitment uses raw fixed-width fields, not RLP or ABI encoding:
|
|
419
|
-
* `keccak256("tempo:
|
|
495
|
+
* `keccak256("tempo:configurable-account:config" || salt || uint64be(version) || uint8(threshold) || uint8(owners.length) || owners)`.
|
|
420
496
|
*
|
|
421
497
|
* @example
|
|
422
498
|
* ```ts twoslash
|
|
423
|
-
* import {
|
|
499
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
424
500
|
*
|
|
425
|
-
* const commitment =
|
|
501
|
+
* const commitment = AccountConfig.getCommitment({
|
|
426
502
|
* owners: [
|
|
427
503
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
428
504
|
* ],
|
|
@@ -431,7 +507,7 @@ export declare namespace getAddress {
|
|
|
431
507
|
* })
|
|
432
508
|
* ```
|
|
433
509
|
*
|
|
434
|
-
* @param config - The complete
|
|
510
|
+
* @param config - The complete account configuration.
|
|
435
511
|
* @returns The configuration commitment.
|
|
436
512
|
*/
|
|
437
513
|
export function getCommitment(config: Input): Hex.Hex {
|
|
@@ -462,9 +538,9 @@ export declare namespace getCommitment {
|
|
|
462
538
|
}
|
|
463
539
|
|
|
464
540
|
/**
|
|
465
|
-
* Computes the digest a
|
|
541
|
+
* Computes the digest a configurable account owner approves (signs).
|
|
466
542
|
*
|
|
467
|
-
* `keccak256("tempo:
|
|
543
|
+
* `keccak256("tempo:configurable-account:signature" || inner_digest || account || uint64be(version))`,
|
|
468
544
|
* where `inner_digest` is the transaction sign payload
|
|
469
545
|
* ({@link ox#TxEnvelopeTempo.(getSignPayload:function)}).
|
|
470
546
|
*
|
|
@@ -474,9 +550,9 @@ export declare namespace getCommitment {
|
|
|
474
550
|
*
|
|
475
551
|
* @example
|
|
476
552
|
* ```ts twoslash
|
|
477
|
-
* import {
|
|
553
|
+
* import { AccountConfig, TxEnvelopeTempo } from 'ox/tempo'
|
|
478
554
|
*
|
|
479
|
-
* const config =
|
|
555
|
+
* const config = AccountConfig.from({
|
|
480
556
|
* owners: [
|
|
481
557
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
482
558
|
* ],
|
|
@@ -488,8 +564,8 @@ export declare namespace getCommitment {
|
|
|
488
564
|
* calls: [],
|
|
489
565
|
* })
|
|
490
566
|
*
|
|
491
|
-
* const digest =
|
|
492
|
-
* account:
|
|
567
|
+
* const digest = AccountConfig.getSignPayload({
|
|
568
|
+
* account: AccountConfig.getAddress(config, {
|
|
493
569
|
* factory: '0x7171717171717171717171717171717171717171'
|
|
494
570
|
* }),
|
|
495
571
|
* config,
|
|
@@ -518,7 +594,7 @@ export function getSignPayload(value: getSignPayload.Value): Hex.Hex {
|
|
|
518
594
|
|
|
519
595
|
export declare namespace getSignPayload {
|
|
520
596
|
type Value = {
|
|
521
|
-
/** The
|
|
597
|
+
/** The configurable account address. */
|
|
522
598
|
account: Address.Address
|
|
523
599
|
/** Configuration whose version applies to the approval. */
|
|
524
600
|
config: Pick<Config<bigint | number>, 'version'>
|
|
@@ -536,13 +612,13 @@ export declare namespace getSignPayload {
|
|
|
536
612
|
}
|
|
537
613
|
|
|
538
614
|
/**
|
|
539
|
-
* Converts
|
|
615
|
+
* Converts an account configuration to its JSON-RPC representation.
|
|
540
616
|
*
|
|
541
617
|
* @example
|
|
542
618
|
* ```ts twoslash
|
|
543
|
-
* import {
|
|
619
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
544
620
|
*
|
|
545
|
-
* const config =
|
|
621
|
+
* const config = AccountConfig.toRpc({
|
|
546
622
|
* owners: [
|
|
547
623
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
548
624
|
* ],
|
|
@@ -550,8 +626,8 @@ export declare namespace getSignPayload {
|
|
|
550
626
|
* })
|
|
551
627
|
* ```
|
|
552
628
|
*
|
|
553
|
-
* @param config - The
|
|
554
|
-
* @returns The JSON-RPC
|
|
629
|
+
* @param config - The account configuration.
|
|
630
|
+
* @returns The JSON-RPC account configuration.
|
|
555
631
|
*/
|
|
556
632
|
export function toRpc(config: Input): Rpc {
|
|
557
633
|
const value = from(config)
|
|
@@ -574,7 +650,7 @@ export declare namespace toRpc {
|
|
|
574
650
|
}
|
|
575
651
|
|
|
576
652
|
/**
|
|
577
|
-
* Converts a {@link ox#
|
|
653
|
+
* Converts a {@link ox#AccountConfig.Config} to its RLP tuple form.
|
|
578
654
|
*
|
|
579
655
|
* Tuple shape: `[salt, version, threshold, [[owner, weight], ...]]`. The
|
|
580
656
|
* 32-byte `salt` encodes as a full fixed-width string; other integers use
|
|
@@ -582,9 +658,9 @@ export declare namespace toRpc {
|
|
|
582
658
|
*
|
|
583
659
|
* @example
|
|
584
660
|
* ```ts twoslash
|
|
585
|
-
* import {
|
|
661
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
586
662
|
*
|
|
587
|
-
* const tuple =
|
|
663
|
+
* const tuple = AccountConfig.toTuple({
|
|
588
664
|
* owners: [
|
|
589
665
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
590
666
|
* ],
|
|
@@ -592,7 +668,7 @@ export declare namespace toRpc {
|
|
|
592
668
|
* })
|
|
593
669
|
* ```
|
|
594
670
|
*
|
|
595
|
-
* @param config - The
|
|
671
|
+
* @param config - The account config.
|
|
596
672
|
* @returns The RLP tuple.
|
|
597
673
|
*/
|
|
598
674
|
export function toTuple(config: Input): Tuple {
|
|
@@ -613,14 +689,75 @@ export function toTuple(config: Input): Tuple {
|
|
|
613
689
|
}
|
|
614
690
|
|
|
615
691
|
/**
|
|
616
|
-
*
|
|
692
|
+
* Derives the configuration that replaces the current one in an owner update.
|
|
693
|
+
*
|
|
694
|
+
* Mirrors the `updateConfig` precompile ([TIP-1109](https://tips.sh/1109)):
|
|
695
|
+
* keeps the current salt, increments the version by one, and replaces the
|
|
696
|
+
* owners and threshold. Owners are sorted into canonical order and the next
|
|
697
|
+
* configuration is validated. The account address does not change.
|
|
698
|
+
*
|
|
699
|
+
* @example
|
|
700
|
+
* ```ts twoslash
|
|
701
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
702
|
+
*
|
|
703
|
+
* const initialConfig = AccountConfig.from({
|
|
704
|
+
* owners: [
|
|
705
|
+
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
706
|
+
* ],
|
|
707
|
+
* threshold: 1,
|
|
708
|
+
* })
|
|
709
|
+
*
|
|
710
|
+
* const config = AccountConfig.update(initialConfig, {
|
|
711
|
+
* owners: [
|
|
712
|
+
* { owner: '0x2222222222222222222222222222222222222222', weight: 1 },
|
|
713
|
+
* ],
|
|
714
|
+
* threshold: 1,
|
|
715
|
+
* })
|
|
716
|
+
* // config.version === 1n, with the initial salt
|
|
717
|
+
* ```
|
|
718
|
+
*
|
|
719
|
+
* @param config - The current account config.
|
|
720
|
+
* @param options - The replacement owners and threshold.
|
|
721
|
+
* @returns The next account config.
|
|
722
|
+
*/
|
|
723
|
+
export function update<numberType = number>(
|
|
724
|
+
config: Input<bigint | number, numberType>,
|
|
725
|
+
options: update.Options<numberType>,
|
|
726
|
+
): Config<bigint, numberType> {
|
|
727
|
+
const current = from(config)
|
|
728
|
+
if (current.version === maxVersion)
|
|
729
|
+
throw new InvalidConfigError({ reason: 'version overflow' })
|
|
730
|
+
return from({
|
|
731
|
+
owners: options.owners,
|
|
732
|
+
salt: current.salt,
|
|
733
|
+
threshold: options.threshold,
|
|
734
|
+
version: current.version + 1n,
|
|
735
|
+
})
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
export declare namespace update {
|
|
739
|
+
type Options<numberType = number> = {
|
|
740
|
+
/** Replacement weighted owners. Sorted into canonical order. */
|
|
741
|
+
owners: readonly Owner<numberType>[]
|
|
742
|
+
/** Replacement minimum total owner weight required for authorization. */
|
|
743
|
+
threshold: numberType
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
type ErrorType =
|
|
747
|
+
| assert.ErrorType
|
|
748
|
+
| InvalidConfigError
|
|
749
|
+
| Errors.GlobalErrorType
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Validates an {@link ox#AccountConfig.Config}. Returns `true`
|
|
617
754
|
* if valid, `false` otherwise.
|
|
618
755
|
*
|
|
619
756
|
* @example
|
|
620
757
|
* ```ts twoslash
|
|
621
|
-
* import {
|
|
758
|
+
* import { AccountConfig } from 'ox/tempo'
|
|
622
759
|
*
|
|
623
|
-
* const valid =
|
|
760
|
+
* const valid = AccountConfig.validate({
|
|
624
761
|
* owners: [
|
|
625
762
|
* { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
626
763
|
* ],
|
|
@@ -629,7 +766,7 @@ export function toTuple(config: Input): Tuple {
|
|
|
629
766
|
* // @log: true
|
|
630
767
|
* ```
|
|
631
768
|
*
|
|
632
|
-
* @param config - The
|
|
769
|
+
* @param config - The account config.
|
|
633
770
|
* @returns Whether the config is valid.
|
|
634
771
|
*/
|
|
635
772
|
export function validate(config: Input): boolean {
|
|
@@ -641,11 +778,11 @@ export function validate(config: Input): boolean {
|
|
|
641
778
|
}
|
|
642
779
|
}
|
|
643
780
|
|
|
644
|
-
/** Thrown when
|
|
781
|
+
/** Thrown when an account config is invalid. */
|
|
645
782
|
export class InvalidConfigError extends Errors.BaseError {
|
|
646
|
-
override readonly name = '
|
|
783
|
+
override readonly name = 'AccountConfig.InvalidConfigError'
|
|
647
784
|
constructor({ reason }: { reason: string }) {
|
|
648
|
-
super(`Invalid
|
|
785
|
+
super(`Invalid account config: ${reason}.`)
|
|
649
786
|
}
|
|
650
787
|
}
|
|
651
788
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { expectTypeOf, test } from 'vitest'
|
|
2
|
+
import type * as Hex from '../core/Hex.js'
|
|
3
|
+
import * as AccountOperation from './AccountOperation.js'
|
|
4
|
+
import type * as TxEnvelopeTempo from './TxEnvelopeTempo.js'
|
|
5
|
+
|
|
6
|
+
declare const transaction: AccountOperation.TransactionOperation
|
|
7
|
+
declare const transactionRpc: AccountOperation.TransactionRpc
|
|
8
|
+
declare const keyAuthorization: AccountOperation.KeyAuthorizationOperation
|
|
9
|
+
declare const keyAuthorizationRpc: AccountOperation.KeyAuthorizationRpc
|
|
10
|
+
declare const operation: AccountOperation.Operation
|
|
11
|
+
declare const operationRpc: AccountOperation.Rpc
|
|
12
|
+
declare const getHashOptions: AccountOperation.getHash.Options
|
|
13
|
+
declare const selectApprovalsOptions: AccountOperation.selectApprovals.Options
|
|
14
|
+
declare const serializeTransactionOptions: AccountOperation.serializeTransaction.Options
|
|
15
|
+
|
|
16
|
+
test('preserves operation kinds during validation', () => {
|
|
17
|
+
expectTypeOf(
|
|
18
|
+
AccountOperation.from(transaction),
|
|
19
|
+
).toEqualTypeOf<AccountOperation.TransactionOperation>()
|
|
20
|
+
expectTypeOf(
|
|
21
|
+
AccountOperation.from(keyAuthorization),
|
|
22
|
+
).toEqualTypeOf<AccountOperation.KeyAuthorizationOperation>()
|
|
23
|
+
expectTypeOf(
|
|
24
|
+
AccountOperation.from(operation),
|
|
25
|
+
).toEqualTypeOf<AccountOperation.Operation>()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('preserves operation kinds during RPC conversion', () => {
|
|
29
|
+
expectTypeOf(
|
|
30
|
+
AccountOperation.fromRpc(transactionRpc),
|
|
31
|
+
).toEqualTypeOf<AccountOperation.TransactionOperation>()
|
|
32
|
+
expectTypeOf(
|
|
33
|
+
AccountOperation.fromRpc(keyAuthorizationRpc),
|
|
34
|
+
).toEqualTypeOf<AccountOperation.KeyAuthorizationOperation>()
|
|
35
|
+
expectTypeOf(
|
|
36
|
+
AccountOperation.toRpc(transaction),
|
|
37
|
+
).toEqualTypeOf<AccountOperation.TransactionRpc>()
|
|
38
|
+
expectTypeOf(
|
|
39
|
+
AccountOperation.toRpc(keyAuthorization),
|
|
40
|
+
).toEqualTypeOf<AccountOperation.KeyAuthorizationRpc>()
|
|
41
|
+
expectTypeOf(
|
|
42
|
+
AccountOperation.fromRpc(operationRpc),
|
|
43
|
+
).toEqualTypeOf<AccountOperation.Operation>()
|
|
44
|
+
expectTypeOf(
|
|
45
|
+
AccountOperation.toRpc(operation),
|
|
46
|
+
).toEqualTypeOf<AccountOperation.Rpc>()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('uses JSON-RPC quantities only in RPC operations', () => {
|
|
50
|
+
expectTypeOf<
|
|
51
|
+
AccountOperation.Operation['config']['version']
|
|
52
|
+
>().toEqualTypeOf<bigint>()
|
|
53
|
+
expectTypeOf<
|
|
54
|
+
AccountOperation.Rpc['config']['version']
|
|
55
|
+
>().toEqualTypeOf<Hex.Hex>()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('operation helpers return narrow types', async () => {
|
|
59
|
+
expectTypeOf(
|
|
60
|
+
AccountOperation.getHash(getHashOptions),
|
|
61
|
+
).toEqualTypeOf<Hex.Hex>()
|
|
62
|
+
expectTypeOf(
|
|
63
|
+
await AccountOperation.selectApprovals(selectApprovalsOptions),
|
|
64
|
+
).toEqualTypeOf<AccountOperation.selectApprovals.ReturnValue>()
|
|
65
|
+
expectTypeOf(
|
|
66
|
+
AccountOperation.serializeTransaction(
|
|
67
|
+
transaction,
|
|
68
|
+
serializeTransactionOptions,
|
|
69
|
+
),
|
|
70
|
+
).toEqualTypeOf<TxEnvelopeTempo.Serialized>()
|
|
71
|
+
})
|