ox 1.0.0-beta.9 → 1.0.0
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 +1143 -0
- package/dist/core/AbiParameters.d.ts.map +1 -1
- package/dist/core/AbiParameters.js +4 -1
- package/dist/core/AbiParameters.js.map +1 -1
- package/dist/core/Rlp.d.ts +27 -5
- package/dist/core/Rlp.d.ts.map +1 -1
- package/dist/core/Rlp.js +40 -4
- package/dist/core/Rlp.js.map +1 -1
- package/dist/core/RpcSchema.d.ts +1 -1
- package/dist/core/internal/abiParameters.d.ts.map +1 -1
- package/dist/core/internal/abiParameters.js +21 -3
- package/dist/core/internal/abiParameters.js.map +1 -1
- package/dist/core/internal/rpcSchemas/eth.d.ts +36 -0
- package/dist/core/internal/rpcSchemas/eth.d.ts.map +1 -1
- package/dist/erc4337/EntryPoint.d.ts +1072 -1
- package/dist/erc4337/EntryPoint.d.ts.map +1 -1
- package/dist/erc4337/EntryPoint.js +872 -0
- package/dist/erc4337/EntryPoint.js.map +1 -1
- package/dist/erc4337/RpcSchema.d.ts +2 -2
- package/dist/erc4337/RpcSchema.d.ts.map +1 -1
- package/dist/erc4337/UserOperation.d.ts +39 -10
- package/dist/erc4337/UserOperation.d.ts.map +1 -1
- package/dist/erc4337/UserOperation.js +62 -48
- package/dist/erc4337/UserOperation.js.map +1 -1
- package/dist/erc4337/UserOperationGas.d.ts +9 -5
- package/dist/erc4337/UserOperationGas.d.ts.map +1 -1
- package/dist/erc4337/UserOperationGas.js +17 -15
- package/dist/erc4337/UserOperationGas.js.map +1 -1
- package/dist/erc4337/UserOperationReceipt.d.ts +4 -4
- package/dist/erc4337/UserOperationReceipt.d.ts.map +1 -1
- package/dist/erc4337/UserOperationReceipt.js.map +1 -1
- package/dist/tempo/Channel.d.ts +8 -14
- package/dist/tempo/Channel.d.ts.map +1 -1
- package/dist/tempo/Channel.js +4 -8
- package/dist/tempo/Channel.js.map +1 -1
- package/dist/tempo/KeyAuthorization.d.ts +5 -5
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/KeyAuthorization.js +4 -4
- package/dist/tempo/KeyAuthorization.js.map +1 -1
- package/dist/tempo/MultisigConfig.d.ts +37 -85
- package/dist/tempo/MultisigConfig.d.ts.map +1 -1
- package/dist/tempo/MultisigConfig.js +39 -83
- package/dist/tempo/MultisigConfig.js.map +1 -1
- package/dist/tempo/PoolId.d.ts +8 -7
- package/dist/tempo/PoolId.d.ts.map +1 -1
- package/dist/tempo/PoolId.js +10 -6
- package/dist/tempo/PoolId.js.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +32 -30
- package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/tempo/SignatureEnvelope.js +56 -51
- package/dist/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/tempo/Transaction.d.ts +16 -5
- package/dist/tempo/Transaction.d.ts.map +1 -1
- package/dist/tempo/Transaction.js +34 -7
- package/dist/tempo/Transaction.js.map +1 -1
- package/dist/tempo/TransactionReceipt.d.ts +3 -3
- package/dist/tempo/TransactionReceipt.d.ts.map +1 -1
- package/dist/tempo/TransactionReceipt.js +8 -1
- package/dist/tempo/TransactionReceipt.js.map +1 -1
- package/dist/tempo/TransactionRequest.d.ts +15 -2
- package/dist/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/tempo/TransactionRequest.js +65 -29
- package/dist/tempo/TransactionRequest.js.map +1 -1
- package/dist/tempo/TxEnvelopeTempo.d.ts +2 -3
- package/dist/tempo/TxEnvelopeTempo.d.ts.map +1 -1
- package/dist/tempo/TxEnvelopeTempo.js +5 -6
- package/dist/tempo/TxEnvelopeTempo.js.map +1 -1
- package/dist/tempo/index.d.ts +6 -26
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +6 -26
- package/dist/tempo/index.js.map +1 -1
- package/dist/zod/Abi.d.ts +214 -0
- package/dist/zod/Abi.d.ts.map +1 -0
- package/dist/zod/Abi.js +5 -0
- package/dist/zod/Abi.js.map +1 -0
- package/dist/zod/AbiConstructor.d.ts +58 -0
- package/dist/zod/AbiConstructor.d.ts.map +1 -0
- package/dist/zod/AbiConstructor.js +18 -0
- package/dist/zod/AbiConstructor.js.map +1 -0
- package/dist/zod/AbiError.d.ts +20 -0
- package/dist/zod/AbiError.d.ts.map +1 -0
- package/dist/zod/AbiError.js +9 -0
- package/dist/zod/AbiError.js.map +1 -0
- package/dist/zod/AbiEvent.d.ts +23 -0
- package/dist/zod/AbiEvent.d.ts.map +1 -0
- package/dist/zod/AbiEvent.js +11 -0
- package/dist/zod/AbiEvent.js.map +1 -0
- package/dist/zod/AbiFallback.d.ts +16 -0
- package/dist/zod/AbiFallback.d.ts.map +1 -0
- package/dist/zod/AbiFallback.js +16 -0
- package/dist/zod/AbiFallback.js.map +1 -0
- package/dist/zod/AbiFunction.d.ts +109 -0
- package/dist/zod/AbiFunction.d.ts.map +1 -0
- package/dist/zod/AbiFunction.js +26 -0
- package/dist/zod/AbiFunction.js.map +1 -0
- package/dist/zod/AbiItem.d.ts +216 -0
- package/dist/zod/AbiItem.d.ts.map +1 -0
- package/dist/zod/AbiItem.js +26 -0
- package/dist/zod/AbiItem.js.map +1 -0
- package/dist/zod/AbiParameter.d.ts +32 -0
- package/dist/zod/AbiParameter.d.ts.map +1 -0
- package/dist/zod/AbiParameter.js +28 -0
- package/dist/zod/AbiParameter.js.map +1 -0
- package/dist/zod/AbiParameters.d.ts +30 -0
- package/dist/zod/AbiParameters.d.ts.map +1 -0
- package/dist/zod/AbiParameters.js +6 -0
- package/dist/zod/AbiParameters.js.map +1 -0
- package/dist/zod/AbiReceive.d.ts +6 -0
- package/dist/zod/AbiReceive.d.ts.map +1 -0
- package/dist/zod/AbiReceive.js +7 -0
- package/dist/zod/AbiReceive.js.map +1 -0
- package/dist/zod/RpcSchema.d.ts +1 -0
- package/dist/zod/RpcSchema.d.ts.map +1 -1
- package/dist/zod/Solidity.d.ts +15 -0
- package/dist/zod/Solidity.d.ts.map +1 -0
- package/dist/zod/Solidity.js +41 -0
- package/dist/zod/Solidity.js.map +1 -0
- package/dist/zod/TypedData.d.ts +226 -0
- package/dist/zod/TypedData.d.ts.map +1 -0
- package/dist/zod/TypedData.js +84 -0
- package/dist/zod/TypedData.js.map +1 -0
- package/dist/zod/internal/rpcSchemas/Eth.d.ts +1 -0
- package/dist/zod/internal/rpcSchemas/Eth.d.ts.map +1 -1
- package/dist/zod/internal/rpcSchemas/Eth.js +5 -0
- package/dist/zod/internal/rpcSchemas/Eth.js.map +1 -1
- package/dist/zod/tempo/AuthorizationTempo.d.ts +0 -20
- package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.d.ts +503 -67
- package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.js +32 -15
- package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
- package/dist/zod/tempo/RpcSchemaTempo.d.ts +216 -34
- package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.d.ts +0 -6
- package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.js +0 -2
- package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/zod/tempo/Transaction.d.ts +1479 -333
- package/dist/zod/tempo/Transaction.d.ts.map +1 -1
- package/dist/zod/tempo/Transaction.js +65 -16
- package/dist/zod/tempo/Transaction.js.map +1 -1
- package/dist/zod/tempo/TransactionRequest.d.ts +410 -57
- package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.js +81 -18
- package/dist/zod/tempo/TransactionRequest.js.map +1 -1
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts +225 -18
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
- package/dist/zod/tempo/TxEnvelopeTempo.js +1 -1
- package/dist/zod/tempo/TxEnvelopeTempo.js.map +1 -1
- package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +0 -3
- package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
- package/dist/zod/tempo/z.d.ts +0 -1
- package/dist/zod/tempo/z.d.ts.map +1 -1
- package/dist/zod/tempo/z.js +0 -1
- package/dist/zod/tempo/z.js.map +1 -1
- package/dist/zod/z.d.ts +12 -0
- package/dist/zod/z.d.ts.map +1 -1
- package/dist/zod/z.js +12 -0
- package/dist/zod/z.js.map +1 -1
- package/package.json +62 -11
- package/src/core/AbiParameters.ts +3 -1
- package/src/core/Rlp.ts +66 -3
- package/src/core/RpcSchema.ts +1 -1
- package/src/core/_test/AbiParameters.decode.test.ts +88 -12
- package/src/core/_test/AbiParameters.encode.test.ts +68 -0
- package/src/core/_test/Rlp.test.ts +101 -0
- package/src/core/internal/abiParameters.ts +21 -3
- package/src/core/internal/rpcSchemas/eth.ts +36 -0
- package/src/erc4337/EntryPoint.ts +875 -1
- package/src/erc4337/RpcSchema.ts +4 -2
- package/src/erc4337/UserOperation.ts +130 -60
- package/src/erc4337/UserOperationGas.ts +36 -28
- package/src/erc4337/UserOperationReceipt.ts +15 -7
- package/src/erc4337/_test/EntryPoint.test.ts +48 -0
- package/src/erc4337/_test/RpcSchema.test-d.ts +56 -0
- package/src/erc4337/_test/UserOperation.snap-d.ts +31 -0
- package/src/erc4337/_test/UserOperation.test.ts +221 -5
- package/src/erc4337/_test/UserOperationGas.test.ts +30 -1
- package/src/tempo/Channel.test.ts +2 -23
- package/src/tempo/Channel.ts +10 -22
- package/src/tempo/KeyAuthorization.test.ts +22 -0
- package/src/tempo/KeyAuthorization.ts +9 -9
- package/src/tempo/MultisigConfig.test.ts +54 -37
- package/src/tempo/MultisigConfig.ts +59 -134
- package/src/tempo/PoolId.test.ts +7 -41
- package/src/tempo/PoolId.ts +15 -10
- package/src/tempo/SignatureEnvelope.test.ts +118 -17
- package/src/tempo/SignatureEnvelope.ts +77 -72
- package/src/tempo/Transaction.test.ts +0 -15
- package/src/tempo/Transaction.ts +63 -12
- package/src/tempo/TransactionReceipt.test.ts +76 -0
- package/src/tempo/TransactionReceipt.ts +11 -5
- package/src/tempo/TransactionRequest.test.ts +174 -1
- package/src/tempo/TransactionRequest.ts +84 -32
- package/src/tempo/TxEnvelopeTempo.test.ts +2 -2
- package/src/tempo/TxEnvelopeTempo.ts +7 -7
- package/src/tempo/e2e.test.ts +228 -50
- package/src/tempo/index.ts +6 -26
- package/src/version.ts +1 -1
- package/src/zod/Abi.ts +5 -0
- package/src/zod/AbiConstructor.ts +24 -0
- package/src/zod/AbiError.ts +9 -0
- package/src/zod/AbiEvent.ts +11 -0
- package/src/zod/AbiFallback.ts +22 -0
- package/src/zod/AbiFunction.ts +32 -0
- package/src/zod/AbiItem.ts +28 -0
- package/src/zod/AbiParameter.ts +36 -0
- package/src/zod/AbiParameters.ts +7 -0
- package/src/zod/AbiReceive.ts +7 -0
- package/src/zod/Solidity.ts +83 -0
- package/src/zod/TypedData.ts +111 -0
- package/src/zod/_test/Abi.test-d.ts +46 -0
- package/src/zod/_test/Abi.test.ts +163 -0
- package/src/zod/_test/TypedData.test-d.ts +20 -0
- package/src/zod/_test/TypedData.test.ts +87 -0
- package/src/zod/_test/z.test-d.ts +6 -0
- package/src/zod/_test/z.test.ts +17 -0
- package/src/zod/internal/rpcSchemas/Eth.ts +6 -0
- package/src/zod/tempo/KeyAuthorization.ts +34 -15
- package/src/zod/tempo/SignatureEnvelope.ts +0 -2
- package/src/zod/tempo/Transaction.ts +84 -22
- package/src/zod/tempo/TransactionRequest.ts +86 -20
- package/src/zod/tempo/TxEnvelopeTempo.ts +1 -1
- package/src/zod/tempo/_test/KeyAuthorization.test.ts +53 -0
- package/src/zod/tempo/_test/SignatureEnvelope.test.ts +0 -2
- package/src/zod/tempo/_test/Transaction.test.ts +155 -0
- package/src/zod/tempo/_test/TransactionRequest.test.ts +44 -0
- package/src/zod/tempo/z.ts +0 -1
- package/src/zod/z.ts +12 -0
- package/dist/tempo/TokenId.d.ts +0 -87
- package/dist/tempo/TokenId.d.ts.map +0 -1
- package/dist/tempo/TokenId.js +0 -123
- package/dist/tempo/TokenId.js.map +0 -1
- package/dist/zod/tempo/TokenId.d.ts +0 -6
- package/dist/zod/tempo/TokenId.d.ts.map +0 -1
- package/dist/zod/tempo/TokenId.js +0 -14
- package/dist/zod/tempo/TokenId.js.map +0 -1
- package/src/CHANGELOG.md +0 -820
- package/src/tempo/TokenId.bench.ts +0 -36
- package/src/tempo/TokenId.test.ts +0 -79
- package/src/tempo/TokenId.ts +0 -141
- package/src/zod/tempo/TokenId.ts +0 -15
- package/src/zod/tempo/_test/TokenId.test-d.ts +0 -17
- package/src/zod/tempo/_test/TokenId.test.ts +0 -21
|
@@ -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 =
|
|
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
|
|
31
|
-
*
|
|
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
|
|
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
|
|
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 `
|
|
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 `<=
|
|
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 >
|
|
118
|
+
if (totalWeight > 0xff)
|
|
116
119
|
throw new InvalidConfigError({
|
|
117
|
-
reason: 'total owner weight exceeds
|
|
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
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
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(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
|
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
|
|
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
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
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`
|
|
310
|
+
* ### From `account`
|
|
315
311
|
*
|
|
316
|
-
* If you already have the permanent `account`
|
|
317
|
-
*
|
|
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`
|
|
384
|
-
*
|
|
385
|
-
*
|
|
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`).
|
package/src/tempo/PoolId.test.ts
CHANGED
|
@@ -2,57 +2,23 @@ import { PoolId } from 'ox/tempo'
|
|
|
2
2
|
import { expect, test } from 'vp/test'
|
|
3
3
|
|
|
4
4
|
test('from', () => {
|
|
5
|
-
|
|
6
|
-
const poolId1 = PoolId.from({
|
|
7
|
-
userToken: 0n,
|
|
8
|
-
validatorToken: 1n,
|
|
9
|
-
})
|
|
10
|
-
expect(poolId1).toMatchInlineSnapshot(
|
|
11
|
-
`"0x24fc92718dfd933b7f831893444e0dc6072ce0fff68198eaf48e86cb1f2ee2dc"`,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
// Test with address token IDs
|
|
15
|
-
const poolId2 = PoolId.from({
|
|
5
|
+
const poolId = PoolId.from({
|
|
16
6
|
userToken: '0x20c0000000000000000000000000000000000000',
|
|
17
7
|
validatorToken: '0x20c0000000000000000000000000000000000001',
|
|
18
8
|
})
|
|
19
|
-
expect(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const poolId3 = PoolId.from({
|
|
23
|
-
userToken: 0n,
|
|
24
|
-
validatorToken: '0x20c0000000000000000000000000000000000001',
|
|
25
|
-
})
|
|
26
|
-
expect(poolId3).toBe(poolId1)
|
|
27
|
-
|
|
28
|
-
const poolId4 = PoolId.from({
|
|
29
|
-
userToken: '0x20c0000000000000000000000000000000000000',
|
|
30
|
-
validatorToken: 1n,
|
|
31
|
-
})
|
|
32
|
-
expect(poolId4).toBe(poolId1)
|
|
9
|
+
expect(poolId).toMatchInlineSnapshot(
|
|
10
|
+
`"0x24fc92718dfd933b7f831893444e0dc6072ce0fff68198eaf48e86cb1f2ee2dc"`,
|
|
11
|
+
)
|
|
33
12
|
})
|
|
34
13
|
|
|
35
14
|
test('order-independent', () => {
|
|
36
15
|
const poolId1 = PoolId.from({
|
|
37
|
-
userToken:
|
|
38
|
-
validatorToken:
|
|
16
|
+
userToken: '0x20c0000000000000000000000000000000000000',
|
|
17
|
+
validatorToken: '0x20c0000000000000000000000000000000000001',
|
|
39
18
|
})
|
|
40
19
|
const poolId2 = PoolId.from({
|
|
41
|
-
userToken: 1n,
|
|
42
|
-
validatorToken: 0n,
|
|
43
|
-
})
|
|
44
|
-
expect(poolId2).toBe(poolId1)
|
|
45
|
-
|
|
46
|
-
const poolId3 = PoolId.from({
|
|
47
20
|
userToken: '0x20c0000000000000000000000000000000000001',
|
|
48
21
|
validatorToken: '0x20c0000000000000000000000000000000000000',
|
|
49
22
|
})
|
|
50
|
-
expect(
|
|
51
|
-
|
|
52
|
-
// Mixed inputs (token id + address) in swapped order.
|
|
53
|
-
const poolId4 = PoolId.from({
|
|
54
|
-
userToken: '0x20c0000000000000000000000000000000000001',
|
|
55
|
-
validatorToken: 0n,
|
|
56
|
-
})
|
|
57
|
-
expect(poolId4).toBe(poolId1)
|
|
23
|
+
expect(poolId2).toBe(poolId1)
|
|
58
24
|
})
|
package/src/tempo/PoolId.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import * as Address from '../core/Address.js'
|
|
1
2
|
import * as Hash from '../core/Hash.js'
|
|
2
3
|
import * as Hex from '../core/Hex.js'
|
|
3
|
-
import * as TokenId from './TokenId.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Converts a user token and validator token to a pool ID.
|
|
@@ -15,8 +15,9 @@ import * as TokenId from './TokenId.js'
|
|
|
15
15
|
* import { PoolId } from 'ox/tempo'
|
|
16
16
|
*
|
|
17
17
|
* const poolId = PoolId.from({
|
|
18
|
-
* userToken:
|
|
19
|
-
* validatorToken:
|
|
18
|
+
* userToken: '0x20c0000000000000000000000000000000000001',
|
|
19
|
+
* validatorToken:
|
|
20
|
+
* '0x20c0000000000000000000000000000000000002'
|
|
20
21
|
* })
|
|
21
22
|
* ```
|
|
22
23
|
*
|
|
@@ -24,9 +25,13 @@ import * as TokenId from './TokenId.js'
|
|
|
24
25
|
* @returns The pool ID.
|
|
25
26
|
*/
|
|
26
27
|
export function from(value: from.Value): Hex.Hex {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const { userToken, validatorToken } = value
|
|
29
|
+
Address.assert(userToken)
|
|
30
|
+
Address.assert(validatorToken)
|
|
31
|
+
const [left, right] =
|
|
32
|
+
userToken.toLowerCase() < validatorToken.toLowerCase()
|
|
33
|
+
? [userToken, validatorToken]
|
|
34
|
+
: [validatorToken, userToken]
|
|
30
35
|
return Hash.keccak256(
|
|
31
36
|
Hex.concat(Hex.padLeft(left, 32), Hex.padLeft(right, 32)),
|
|
32
37
|
)
|
|
@@ -34,9 +39,9 @@ export function from(value: from.Value): Hex.Hex {
|
|
|
34
39
|
|
|
35
40
|
export declare namespace from {
|
|
36
41
|
export type Value = {
|
|
37
|
-
/** User token. */
|
|
38
|
-
userToken:
|
|
39
|
-
/** Validator token. */
|
|
40
|
-
validatorToken:
|
|
42
|
+
/** User token address. */
|
|
43
|
+
userToken: Address.Address
|
|
44
|
+
/** Validator token address. */
|
|
45
|
+
validatorToken: Address.Address
|
|
41
46
|
}
|
|
42
47
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Hex,
|
|
4
4
|
P256,
|
|
5
5
|
PublicKey,
|
|
6
|
+
Rlp,
|
|
6
7
|
Secp256k1,
|
|
7
8
|
Signature,
|
|
8
9
|
WebAuthnP256,
|
|
@@ -1125,7 +1126,7 @@ describe('from', () => {
|
|
|
1125
1126
|
],
|
|
1126
1127
|
})
|
|
1127
1128
|
|
|
1128
|
-
test('behavior: derives `account
|
|
1129
|
+
test('behavior: derives `account` from `genesisConfig`', () => {
|
|
1129
1130
|
const envelope = SignatureEnvelope.from({
|
|
1130
1131
|
genesisConfig,
|
|
1131
1132
|
signatures: [SignatureEnvelope.from(signature_secp256k1)],
|
|
@@ -1134,7 +1135,6 @@ describe('from', () => {
|
|
|
1134
1135
|
expect(envelope).toMatchObject({
|
|
1135
1136
|
type: 'multisig',
|
|
1136
1137
|
account: MultisigConfig.getAddress(genesisConfig),
|
|
1137
|
-
genesisConfigId: MultisigConfig.toId(genesisConfig),
|
|
1138
1138
|
})
|
|
1139
1139
|
expect('genesisConfig' in envelope).toBe(false)
|
|
1140
1140
|
expect((envelope as SignatureEnvelope.Multisig).init).toBeUndefined()
|
|
@@ -1171,19 +1171,16 @@ describe('from', () => {
|
|
|
1171
1171
|
expect((envelope as SignatureEnvelope.Multisig).init).toEqual(otherConfig)
|
|
1172
1172
|
})
|
|
1173
1173
|
|
|
1174
|
-
test('behavior: `{account
|
|
1174
|
+
test('behavior: `{ account }` form still works', () => {
|
|
1175
1175
|
const account = MultisigConfig.getAddress(genesisConfig)
|
|
1176
|
-
const genesisConfigId = MultisigConfig.toId(genesisConfig)
|
|
1177
1176
|
const envelope = SignatureEnvelope.from({
|
|
1178
1177
|
account,
|
|
1179
|
-
genesisConfigId,
|
|
1180
1178
|
signatures: [SignatureEnvelope.from(signature_secp256k1)],
|
|
1181
1179
|
})
|
|
1182
1180
|
|
|
1183
1181
|
expect(envelope).toMatchObject({
|
|
1184
1182
|
type: 'multisig',
|
|
1185
1183
|
account,
|
|
1186
|
-
genesisConfigId,
|
|
1187
1184
|
})
|
|
1188
1185
|
})
|
|
1189
1186
|
})
|
|
@@ -1860,9 +1857,8 @@ describe('sortMultisigApprovals', () => {
|
|
|
1860
1857
|
expect(recovered).toEqual(ascending.map((owner) => owner.address))
|
|
1861
1858
|
})
|
|
1862
1859
|
|
|
1863
|
-
test('behavior: `genesisConfig` and `{account
|
|
1860
|
+
test('behavior: `genesisConfig` and `{ account }` produce identical ordering', () => {
|
|
1864
1861
|
const account = MultisigConfig.getAddress(genesisConfig)
|
|
1865
|
-
const genesisConfigId = MultisigConfig.toId(genesisConfig)
|
|
1866
1862
|
const signatures = owners.map((owner) => owner.signature)
|
|
1867
1863
|
|
|
1868
1864
|
const fromConfig = SignatureEnvelope.sortMultisigApprovals({
|
|
@@ -1870,13 +1866,12 @@ describe('sortMultisigApprovals', () => {
|
|
|
1870
1866
|
payload,
|
|
1871
1867
|
signatures,
|
|
1872
1868
|
})
|
|
1873
|
-
const
|
|
1869
|
+
const fromAccount = SignatureEnvelope.sortMultisigApprovals({
|
|
1874
1870
|
account,
|
|
1875
|
-
genesisConfigId,
|
|
1876
1871
|
payload,
|
|
1877
1872
|
signatures,
|
|
1878
1873
|
})
|
|
1879
|
-
expect(fromConfig).toEqual(
|
|
1874
|
+
expect(fromConfig).toEqual(fromAccount)
|
|
1880
1875
|
})
|
|
1881
1876
|
})
|
|
1882
1877
|
|
|
@@ -2883,8 +2878,6 @@ describe('CoercionError', () => {
|
|
|
2883
2878
|
|
|
2884
2879
|
describe('multisig', () => {
|
|
2885
2880
|
const account = '0x8ba6d26ff5c4e82ba0c8caf8c8ca794e1489a7ae'
|
|
2886
|
-
const genesisConfigId =
|
|
2887
|
-
'0x01781fe551182476f2422c759e82d81c92e3263737afbbad57def6e8b69d21f5'
|
|
2888
2881
|
|
|
2889
2882
|
// P256 signatures do not carry `yParity` in the wire format, so use a clean
|
|
2890
2883
|
// inner signature for round-trip equality checks.
|
|
@@ -2897,7 +2890,6 @@ describe('multisig', () => {
|
|
|
2897
2890
|
const envelope = SignatureEnvelope.from({
|
|
2898
2891
|
type: 'multisig',
|
|
2899
2892
|
account,
|
|
2900
|
-
genesisConfigId,
|
|
2901
2893
|
signatures: [SignatureEnvelope.from(signature_secp256k1), innerP256],
|
|
2902
2894
|
})
|
|
2903
2895
|
|
|
@@ -2906,11 +2898,32 @@ describe('multisig', () => {
|
|
|
2906
2898
|
expect(serialized.startsWith('0x05')).toBe(true)
|
|
2907
2899
|
})
|
|
2908
2900
|
|
|
2901
|
+
test('serialize: wire shape is `0x05 || rlp([account, signatures])`', () => {
|
|
2902
|
+
const deterministic = SignatureEnvelope.from({
|
|
2903
|
+
type: 'multisig',
|
|
2904
|
+
account,
|
|
2905
|
+
signatures: [innerP256],
|
|
2906
|
+
})
|
|
2907
|
+
expect(SignatureEnvelope.serialize(deterministic)).toMatchInlineSnapshot(
|
|
2908
|
+
`"0x05f89b948ba6d26ff5c4e82ba0c8caf8c8ca794e1489a7aef884b88201ccbb3485d4726235f13cb15ef394fb7158179fb7b1925eccec0147671090c52e77c3c53373cc1e3b05e7c23f609deb17cea8fe097300c45411237e9fe4166b35ad8ac16e167d6992c3e120d7f17d2376bc1cbcf30c46ba6dd00ce07303e742f511edf6ce1c32de66846f56afa7be1cbd729bc35750b6d0cdcf3ec9d75461aba001"`,
|
|
2909
|
+
)
|
|
2910
|
+
})
|
|
2911
|
+
|
|
2909
2912
|
test('serialize/deserialize round-trip', () => {
|
|
2910
2913
|
const serialized = SignatureEnvelope.serialize(envelope)
|
|
2911
2914
|
expect(SignatureEnvelope.deserialize(serialized)).toEqual(envelope)
|
|
2912
2915
|
})
|
|
2913
2916
|
|
|
2917
|
+
test('deserialize: rejects the empty `init` placeholder (`0x80`)', () => {
|
|
2918
|
+
const withPlaceholder = Hex.concat(
|
|
2919
|
+
'0x05',
|
|
2920
|
+
Rlp.fromHex([account, [SignatureEnvelope.serialize(innerP256)], '0x']),
|
|
2921
|
+
)
|
|
2922
|
+
expect(() => SignatureEnvelope.deserialize(withPlaceholder)).toThrowError(
|
|
2923
|
+
SignatureEnvelope.InvalidSerializedError,
|
|
2924
|
+
)
|
|
2925
|
+
})
|
|
2926
|
+
|
|
2914
2927
|
test('getType', () => {
|
|
2915
2928
|
expect(SignatureEnvelope.getType(envelope)).toBe('multisig')
|
|
2916
2929
|
})
|
|
@@ -2936,6 +2949,97 @@ describe('multisig', () => {
|
|
|
2936
2949
|
).toThrowError()
|
|
2937
2950
|
})
|
|
2938
2951
|
|
|
2952
|
+
test('assert: rejects keychain owner approvals', () => {
|
|
2953
|
+
expect(() =>
|
|
2954
|
+
SignatureEnvelope.assert({
|
|
2955
|
+
type: 'multisig',
|
|
2956
|
+
account,
|
|
2957
|
+
signatures: [signature_keychain_secp256k1],
|
|
2958
|
+
} as never),
|
|
2959
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
2960
|
+
`[SignatureEnvelope.InvalidMultisigApprovalError: Invalid native multisig owner approval: keychain owner approvals are not allowed.]`,
|
|
2961
|
+
)
|
|
2962
|
+
})
|
|
2963
|
+
|
|
2964
|
+
describe('nested approvals', () => {
|
|
2965
|
+
const nestedAccount = '0x1111111111111111111111111111111111111111'
|
|
2966
|
+
const nested = SignatureEnvelope.from({
|
|
2967
|
+
type: 'multisig',
|
|
2968
|
+
account: nestedAccount,
|
|
2969
|
+
signatures: [innerP256],
|
|
2970
|
+
})
|
|
2971
|
+
|
|
2972
|
+
test('serialize/deserialize round-trip with a nested multisig approval', () => {
|
|
2973
|
+
const parent = SignatureEnvelope.from({
|
|
2974
|
+
type: 'multisig',
|
|
2975
|
+
account,
|
|
2976
|
+
signatures: [innerP256, nested],
|
|
2977
|
+
})
|
|
2978
|
+
const serialized = SignatureEnvelope.serialize(parent)
|
|
2979
|
+
expect(SignatureEnvelope.deserialize(serialized)).toEqual(parent)
|
|
2980
|
+
})
|
|
2981
|
+
|
|
2982
|
+
test('assert: accepts the maximum nesting depth', () => {
|
|
2983
|
+
const depth3 = SignatureEnvelope.from({
|
|
2984
|
+
type: 'multisig',
|
|
2985
|
+
account,
|
|
2986
|
+
signatures: [
|
|
2987
|
+
SignatureEnvelope.from({
|
|
2988
|
+
type: 'multisig',
|
|
2989
|
+
account: nestedAccount,
|
|
2990
|
+
signatures: [nested],
|
|
2991
|
+
}),
|
|
2992
|
+
],
|
|
2993
|
+
})
|
|
2994
|
+
expect(() => SignatureEnvelope.assert(depth3)).not.toThrowError()
|
|
2995
|
+
})
|
|
2996
|
+
|
|
2997
|
+
test('assert: rejects nesting deeper than the maximum', () => {
|
|
2998
|
+
const depth4 = SignatureEnvelope.from({
|
|
2999
|
+
type: 'multisig',
|
|
3000
|
+
account,
|
|
3001
|
+
signatures: [
|
|
3002
|
+
SignatureEnvelope.from({
|
|
3003
|
+
type: 'multisig',
|
|
3004
|
+
account: nestedAccount,
|
|
3005
|
+
signatures: [
|
|
3006
|
+
SignatureEnvelope.from({
|
|
3007
|
+
type: 'multisig',
|
|
3008
|
+
account: nestedAccount,
|
|
3009
|
+
signatures: [nested],
|
|
3010
|
+
}),
|
|
3011
|
+
],
|
|
3012
|
+
}),
|
|
3013
|
+
],
|
|
3014
|
+
})
|
|
3015
|
+
expect(() =>
|
|
3016
|
+
SignatureEnvelope.assert(depth4),
|
|
3017
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
3018
|
+
`[SignatureEnvelope.InvalidMultisigApprovalError: Invalid native multisig owner approval: multisig nesting depth exceeds 3.]`,
|
|
3019
|
+
)
|
|
3020
|
+
})
|
|
3021
|
+
|
|
3022
|
+
test('assert: rejects nested approvals carrying `init`', () => {
|
|
3023
|
+
expect(() =>
|
|
3024
|
+
SignatureEnvelope.assert({
|
|
3025
|
+
type: 'multisig',
|
|
3026
|
+
account,
|
|
3027
|
+
signatures: [
|
|
3028
|
+
{
|
|
3029
|
+
...nested,
|
|
3030
|
+
init: {
|
|
3031
|
+
threshold: 1,
|
|
3032
|
+
owners: [{ owner: nestedAccount, weight: 1 }],
|
|
3033
|
+
},
|
|
3034
|
+
},
|
|
3035
|
+
],
|
|
3036
|
+
} as never),
|
|
3037
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
3038
|
+
`[SignatureEnvelope.InvalidMultisigApprovalError: Invalid native multisig owner approval: nested multisig owner approvals cannot carry \`init\`.]`,
|
|
3039
|
+
)
|
|
3040
|
+
})
|
|
3041
|
+
})
|
|
3042
|
+
|
|
2939
3043
|
describe('init (bootstrap)', () => {
|
|
2940
3044
|
const init = {
|
|
2941
3045
|
salt: `0x${'00'.repeat(32)}` as const,
|
|
@@ -2951,7 +3055,6 @@ describe('multisig', () => {
|
|
|
2951
3055
|
const bootstrapEnvelope = SignatureEnvelope.from({
|
|
2952
3056
|
type: 'multisig',
|
|
2953
3057
|
account,
|
|
2954
|
-
genesisConfigId,
|
|
2955
3058
|
signatures: [SignatureEnvelope.from(signature_secp256k1), innerP256],
|
|
2956
3059
|
init,
|
|
2957
3060
|
})
|
|
@@ -2967,7 +3070,6 @@ describe('multisig', () => {
|
|
|
2967
3070
|
const salted = SignatureEnvelope.from({
|
|
2968
3071
|
type: 'multisig',
|
|
2969
3072
|
account,
|
|
2970
|
-
genesisConfigId,
|
|
2971
3073
|
signatures: [SignatureEnvelope.from(signature_secp256k1), innerP256],
|
|
2972
3074
|
init: { ...init, salt: `0x${'42'.repeat(32)}` },
|
|
2973
3075
|
})
|
|
@@ -3021,7 +3123,6 @@ describe('multisig', () => {
|
|
|
3021
3123
|
SignatureEnvelope.assert({
|
|
3022
3124
|
type: 'multisig',
|
|
3023
3125
|
account,
|
|
3024
|
-
genesisConfigId,
|
|
3025
3126
|
signatures: [],
|
|
3026
3127
|
init: { threshold: 1, owners: [] },
|
|
3027
3128
|
} as never),
|