ox 1.7.2 → 1.7.5
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 +43 -0
- package/dist/core/AbiEvent.d.ts.map +1 -1
- package/dist/core/AbiEvent.js +10 -9
- package/dist/core/AbiEvent.js.map +1 -1
- package/dist/core/Blobs.d.ts.map +1 -1
- package/dist/core/Blobs.js +6 -2
- package/dist/core/Blobs.js.map +1 -1
- package/dist/core/Signature.d.ts +6 -5
- package/dist/core/Signature.d.ts.map +1 -1
- package/dist/core/Signature.js +17 -7
- package/dist/core/Signature.js.map +1 -1
- package/dist/core/Siwe.d.ts.map +1 -1
- package/dist/core/Siwe.js +21 -1
- package/dist/core/Siwe.js.map +1 -1
- package/dist/tempo/KeyAuthorization.d.ts +43 -39
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/KeyAuthorization.js +24 -4
- package/dist/tempo/KeyAuthorization.js.map +1 -1
- package/dist/tempo/MultisigConfig.d.ts +18 -15
- package/dist/tempo/MultisigConfig.d.ts.map +1 -1
- package/dist/tempo/MultisigConfig.js +49 -20
- package/dist/tempo/MultisigConfig.js.map +1 -1
- package/dist/tempo/MultisigOperation.d.ts +45 -28
- package/dist/tempo/MultisigOperation.d.ts.map +1 -1
- package/dist/tempo/MultisigOperation.js +81 -131
- package/dist/tempo/MultisigOperation.js.map +1 -1
- package/dist/tempo/MultisigSimulation.d.ts +85 -0
- package/dist/tempo/MultisigSimulation.d.ts.map +1 -0
- package/dist/tempo/MultisigSimulation.js +112 -0
- package/dist/tempo/MultisigSimulation.js.map +1 -0
- package/dist/tempo/RpcSchemaTempo.d.ts +20 -10
- package/dist/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +74 -153
- package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/tempo/SignatureEnvelope.js +130 -187
- package/dist/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/tempo/TransactionRequest.d.ts +9 -7
- package/dist/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/tempo/TransactionRequest.js +12 -7
- package/dist/tempo/TransactionRequest.js.map +1 -1
- package/dist/tempo/index.d.ts +7 -5
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +7 -5
- package/dist/tempo/index.js.map +1 -1
- package/dist/zod/tempo/AuthorizationTempo.d.ts +360 -140
- package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.d.ts +247 -487
- package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.js +29 -31
- package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
- package/dist/zod/tempo/MultisigOperation.d.ts +0 -10
- package/dist/zod/tempo/MultisigOperation.d.ts.map +1 -1
- package/dist/zod/tempo/MultisigOperation.js +0 -3
- package/dist/zod/tempo/MultisigOperation.js.map +1 -1
- package/dist/zod/tempo/MultisigSimulation.d.ts +52 -0
- package/dist/zod/tempo/MultisigSimulation.d.ts.map +1 -0
- package/dist/zod/tempo/MultisigSimulation.js +44 -0
- package/dist/zod/tempo/MultisigSimulation.js.map +1 -0
- package/dist/zod/tempo/RpcSchemaTempo.d.ts +357 -422
- package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/zod/tempo/RpcSchemaTempo.js +19 -10
- package/dist/zod/tempo/RpcSchemaTempo.js.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.d.ts +108 -42
- package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.js +21 -19
- package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/zod/tempo/Transaction.d.ts +678 -666
- package/dist/zod/tempo/Transaction.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.d.ts +580 -619
- package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.js +18 -10
- package/dist/zod/tempo/TransactionRequest.js.map +1 -1
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts +327 -213
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
- package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +105 -3
- package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
- package/dist/zod/tempo/z.d.ts +1 -1
- package/dist/zod/tempo/z.d.ts.map +1 -1
- package/dist/zod/tempo/z.js +1 -1
- package/dist/zod/tempo/z.js.map +1 -1
- package/package.json +9 -9
- package/src/core/AbiEvent.ts +11 -9
- package/src/core/Blobs.ts +6 -2
- package/src/core/Signature.ts +41 -11
- package/src/core/Siwe.ts +20 -1
- package/src/core/_test/AbiEvent.test.ts +45 -0
- package/src/core/_test/Blobs.test.ts +22 -0
- package/src/core/_test/Signature.test.ts +166 -0
- package/src/core/_test/Siwe.test.ts +100 -1
- package/src/tempo/AuthorizationTempo.test.ts +8 -0
- package/src/tempo/KeyAuthorization.test-d.ts +16 -74
- package/src/tempo/KeyAuthorization.test.ts +113 -14
- package/src/tempo/KeyAuthorization.ts +110 -66
- package/src/tempo/MultisigConfig.test.ts +44 -20
- package/src/tempo/MultisigConfig.ts +65 -23
- package/src/tempo/MultisigOperation.test-d.ts +8 -6
- package/src/tempo/MultisigOperation.test.ts +187 -591
- package/src/tempo/MultisigOperation.ts +129 -205
- package/src/tempo/MultisigSimulation.test-d.ts +33 -0
- package/src/tempo/MultisigSimulation.test.ts +194 -0
- package/src/tempo/MultisigSimulation.ts +192 -0
- package/src/tempo/RpcSchemaTempo.test-d.ts +45 -10
- package/src/tempo/RpcSchemaTempo.ts +15 -6
- package/src/tempo/SignatureEnvelope.test-d.ts +27 -101
- package/src/tempo/SignatureEnvelope.test.ts +330 -533
- package/src/tempo/SignatureEnvelope.ts +198 -310
- package/src/tempo/Transaction.test.ts +61 -0
- package/src/tempo/TransactionRequest.test-d.ts +7 -7
- package/src/tempo/TransactionRequest.test.ts +81 -223
- package/src/tempo/TransactionRequest.ts +34 -13
- package/src/tempo/index.ts +7 -5
- package/src/tempo/multisig.e2e.test.ts +329 -818
- package/src/version.ts +1 -1
- package/src/zod/tempo/KeyAuthorization.ts +50 -39
- package/src/zod/tempo/MultisigOperation.ts +0 -3
- package/src/zod/tempo/MultisigSimulation.ts +53 -0
- package/src/zod/tempo/RpcSchemaTempo.ts +20 -10
- package/src/zod/tempo/SignatureEnvelope.ts +46 -59
- package/src/zod/tempo/TransactionRequest.ts +28 -14
- package/src/zod/tempo/_test/KeyAuthorization.test.ts +66 -30
- package/src/zod/tempo/_test/MultisigOperation.test.ts +0 -2
- package/src/zod/tempo/_test/MultisigSimulation.test-d.ts +13 -0
- package/src/zod/tempo/_test/MultisigSimulation.test.ts +53 -0
- package/src/zod/tempo/_test/RpcSchemaTempo.test-d.ts +19 -2
- package/src/zod/tempo/_test/RpcSchemaTempo.test.ts +46 -4
- package/src/zod/tempo/_test/SignatureEnvelope.test.ts +108 -129
- package/src/zod/tempo/_test/TransactionRequest.test.ts +17 -168
- package/src/zod/tempo/z.ts +1 -1
- package/dist/tempo/MultisigWitness.d.ts +0 -106
- package/dist/tempo/MultisigWitness.d.ts.map +0 -1
- package/dist/tempo/MultisigWitness.js +0 -118
- package/dist/tempo/MultisigWitness.js.map +0 -1
- package/dist/zod/tempo/MultisigWitness.d.ts +0 -152
- package/dist/zod/tempo/MultisigWitness.d.ts.map +0 -1
- package/dist/zod/tempo/MultisigWitness.js +0 -76
- package/dist/zod/tempo/MultisigWitness.js.map +0 -1
- package/src/tempo/MultisigWitness.test-d.ts +0 -42
- package/src/tempo/MultisigWitness.test.ts +0 -288
- package/src/tempo/MultisigWitness.ts +0 -210
- package/src/zod/tempo/MultisigWitness.ts +0 -101
- package/src/zod/tempo/_test/MultisigWitness.test-d.ts +0 -13
- package/src/zod/tempo/_test/MultisigWitness.test.ts +0 -149
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { MultisigConfig, MultisigSimulation } from 'ox/tempo'
|
|
2
|
+
import { describe, expect, test } from 'vp/test'
|
|
3
|
+
|
|
4
|
+
const config =
|
|
5
|
+
'0xf852a011111111111111111111111111111111111111111111111111111111111111118002eed694111111111111111111111111111111111111111101d694bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01' as const
|
|
6
|
+
const rpc = {
|
|
7
|
+
approvals: [
|
|
8
|
+
{
|
|
9
|
+
keyType: 'webAuthn',
|
|
10
|
+
keyData: '0x0102030405',
|
|
11
|
+
owner: '0x1111111111111111111111111111111111111111',
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
config,
|
|
15
|
+
} as const satisfies MultisigSimulation.Rpc
|
|
16
|
+
|
|
17
|
+
describe('fromRpc', () => {
|
|
18
|
+
test('behavior: decodes the configuration', () => {
|
|
19
|
+
expect(MultisigSimulation.fromRpc(rpc)).toMatchInlineSnapshot(`
|
|
20
|
+
{
|
|
21
|
+
"approvals": [
|
|
22
|
+
{
|
|
23
|
+
"keyData": "0x0102030405",
|
|
24
|
+
"keyType": "webAuthn",
|
|
25
|
+
"owner": "0x1111111111111111111111111111111111111111",
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
"config": {
|
|
29
|
+
"owners": [
|
|
30
|
+
{
|
|
31
|
+
"owner": "0x1111111111111111111111111111111111111111",
|
|
32
|
+
"weight": 1,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"owner": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
36
|
+
"weight": 1,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
"salt": "0x1111111111111111111111111111111111111111111111111111111111111111",
|
|
40
|
+
"threshold": 2,
|
|
41
|
+
"version": 0n,
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
`)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('behavior: preserves the maximum uint64 configuration version', () => {
|
|
48
|
+
const config =
|
|
49
|
+
'0xf843a0000000000000000000000000000000000000000000000000000000000000000088ffffffffffffffff01d7d694111111111111111111111111111111111111111101' as const
|
|
50
|
+
|
|
51
|
+
expect(
|
|
52
|
+
MultisigSimulation.fromRpc({ ...rpc, approvals: [], config }).config
|
|
53
|
+
.version,
|
|
54
|
+
).toMatchInlineSnapshot(`18446744073709551615n`)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('error: rejects excess root approvals', () => {
|
|
58
|
+
expect(() =>
|
|
59
|
+
MultisigSimulation.fromRpc({
|
|
60
|
+
...rpc,
|
|
61
|
+
approvals: Array.from({ length: 9 }, () => rpc.approvals[0]),
|
|
62
|
+
}),
|
|
63
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
64
|
+
`[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: approval count exceeds 8.]`,
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
test('error: rejects nested approvals', () => {
|
|
68
|
+
expect(() =>
|
|
69
|
+
MultisigSimulation.fromRpc({
|
|
70
|
+
...rpc,
|
|
71
|
+
approvals: [{ type: 'multisig', spec: rpc }],
|
|
72
|
+
} as never),
|
|
73
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
74
|
+
`[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: only untagged primitive owner approvals are allowed.]`,
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('error: rejects trailing configuration bytes', () => {
|
|
79
|
+
expect(() =>
|
|
80
|
+
MultisigSimulation.fromRpc({ ...rpc, config: `${config}00` }),
|
|
81
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
82
|
+
`[Rlp.TrailingBytesError: RLP payload encodes a single item, but \`1\` trailing byte remains.]`,
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('error: rejects malformed configuration RLP', () => {
|
|
87
|
+
expect(() =>
|
|
88
|
+
MultisigSimulation.fromRpc({ ...rpc, config: '0xf8' }),
|
|
89
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
90
|
+
`[Cursor.PositionOutOfBoundsError: Position \`1\` is out of bounds (\`0 < position < 1\`).]`,
|
|
91
|
+
)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('error: rejects a non-list configuration', () => {
|
|
95
|
+
expect(() =>
|
|
96
|
+
MultisigSimulation.fromRpc({ ...rpc, config: '0x01' }),
|
|
97
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
98
|
+
`[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: invalid config encoding.]`,
|
|
99
|
+
)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('error: rejects noncanonical configuration integers', () => {
|
|
103
|
+
const noncanonical = config
|
|
104
|
+
.replace('0xf852', '0xf853')
|
|
105
|
+
.replace('118002', '11810002') as `0x${string}`
|
|
106
|
+
|
|
107
|
+
expect(() =>
|
|
108
|
+
MultisigSimulation.fromRpc({ ...rpc, config: noncanonical }),
|
|
109
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
110
|
+
`[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: invalid config encoding.]`,
|
|
111
|
+
)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('toRpc', () => {
|
|
116
|
+
test('behavior: encodes configurations and shims long key data', () => {
|
|
117
|
+
expect(MultisigSimulation.toRpc(MultisigSimulation.fromRpc(rpc)))
|
|
118
|
+
.toMatchInlineSnapshot(`
|
|
119
|
+
{
|
|
120
|
+
"approvals": [
|
|
121
|
+
{
|
|
122
|
+
"keyData": "0x0005",
|
|
123
|
+
"keyType": "webAuthn",
|
|
124
|
+
"owner": "0x1111111111111111111111111111111111111111",
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
"config": "0xf852a011111111111111111111111111111111111111111111111111111111111111118002eed694111111111111111111111111111111111111111101d694bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01",
|
|
128
|
+
}
|
|
129
|
+
`)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test('behavior: preserves short key data', () => {
|
|
133
|
+
const spec = MultisigSimulation.fromRpc({
|
|
134
|
+
...rpc,
|
|
135
|
+
approvals: [{ ...rpc.approvals[0], keyData: '0x0102' }],
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
expect(MultisigSimulation.toRpc(spec).approvals).toMatchInlineSnapshot(`
|
|
139
|
+
[
|
|
140
|
+
{
|
|
141
|
+
"keyData": "0x0102",
|
|
142
|
+
"keyType": "webAuthn",
|
|
143
|
+
"owner": "0x1111111111111111111111111111111111111111",
|
|
144
|
+
},
|
|
145
|
+
]
|
|
146
|
+
`)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('behavior: encodes the maximum uint64 configuration version', () => {
|
|
150
|
+
const spec = MultisigSimulation.fromRpc(rpc)
|
|
151
|
+
|
|
152
|
+
expect(
|
|
153
|
+
MultisigSimulation.toRpc({
|
|
154
|
+
...spec,
|
|
155
|
+
approvals: [],
|
|
156
|
+
config: MultisigConfig.from({
|
|
157
|
+
owners: [
|
|
158
|
+
{
|
|
159
|
+
owner: '0x1111111111111111111111111111111111111111',
|
|
160
|
+
weight: 1,
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
threshold: 1,
|
|
164
|
+
version: MultisigConfig.maxVersion,
|
|
165
|
+
}),
|
|
166
|
+
}).config,
|
|
167
|
+
).toMatchInlineSnapshot(
|
|
168
|
+
`"0xf843a0000000000000000000000000000000000000000000000000000000000000000088ffffffffffffffff01d7d694111111111111111111111111111111111111111101"`,
|
|
169
|
+
)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test('error: rejects excess root approvals', () => {
|
|
173
|
+
const spec = MultisigSimulation.fromRpc(rpc)
|
|
174
|
+
|
|
175
|
+
expect(() =>
|
|
176
|
+
MultisigSimulation.toRpc({
|
|
177
|
+
...spec,
|
|
178
|
+
approvals: Array.from({ length: 9 }, () => spec.approvals[0]!),
|
|
179
|
+
}),
|
|
180
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
181
|
+
`[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: approval count exceeds 8.]`,
|
|
182
|
+
)
|
|
183
|
+
})
|
|
184
|
+
test('error: rejects nested approvals', () => {
|
|
185
|
+
expect(() =>
|
|
186
|
+
MultisigSimulation.toRpc({
|
|
187
|
+
...rpc,
|
|
188
|
+
approvals: [{ type: 'multisig', spec: rpc }],
|
|
189
|
+
} as never),
|
|
190
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
191
|
+
`[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: only untagged primitive owner approvals are allowed.]`,
|
|
192
|
+
)
|
|
193
|
+
})
|
|
194
|
+
})
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import * as Address from '../core/Address.js'
|
|
2
|
+
import * as Errors from '../core/Errors.js'
|
|
3
|
+
import * as Hex from '../core/Hex.js'
|
|
4
|
+
import type { Compute } from '../core/internal/types.js'
|
|
5
|
+
import * as Rlp from '../core/Rlp.js'
|
|
6
|
+
import * as MultisigConfig from './MultisigConfig.js'
|
|
7
|
+
import type * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
8
|
+
|
|
9
|
+
/** Native multisig owner approval used for RPC simulation. */
|
|
10
|
+
export type Approval = PrimitiveApproval
|
|
11
|
+
|
|
12
|
+
/** JSON-RPC native multisig owner approval used for RPC simulation. */
|
|
13
|
+
export type ApprovalRpc = PrimitiveApproval
|
|
14
|
+
|
|
15
|
+
/** Primitive owner approval used for RPC simulation. */
|
|
16
|
+
export type PrimitiveApproval = {
|
|
17
|
+
/** Optional signature-specific gas-estimation data. */
|
|
18
|
+
keyData?: Hex.Hex | undefined
|
|
19
|
+
/** Signature type to model. Omission uses a maximum-size WebAuthn signature. */
|
|
20
|
+
keyType?: SignatureEnvelope.Type | undefined
|
|
21
|
+
/** Configured owner address. */
|
|
22
|
+
owner: Address.Address
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** JSON-RPC representation of a native multisig simulation spec. */
|
|
26
|
+
export type Rpc = Compute<{
|
|
27
|
+
/** Owner approvals to model. */
|
|
28
|
+
approvals: readonly ApprovalRpc[]
|
|
29
|
+
/** Canonical RLP-encoded applicable configuration. */
|
|
30
|
+
config: Hex.Hex
|
|
31
|
+
}>
|
|
32
|
+
|
|
33
|
+
/** Native multisig spec used to construct an RPC simulation signature. */
|
|
34
|
+
export type Spec = Compute<{
|
|
35
|
+
/** Owner approvals to model. */
|
|
36
|
+
approvals: readonly Approval[]
|
|
37
|
+
/** Complete applicable configuration. */
|
|
38
|
+
config: MultisigConfig.Config
|
|
39
|
+
}>
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Converts a JSON-RPC multisig simulation spec to its domain representation.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts twoslash
|
|
46
|
+
* // @noErrors
|
|
47
|
+
* import { MultisigSimulation } from 'ox/tempo'
|
|
48
|
+
*
|
|
49
|
+
* const spec = MultisigSimulation.fromRpc(specRpc)
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @param spec - JSON-RPC multisig simulation spec.
|
|
53
|
+
* @returns The multisig simulation spec with decoded configurations.
|
|
54
|
+
*/
|
|
55
|
+
export function fromRpc(spec: Rpc): Spec {
|
|
56
|
+
const { approvals, config } = spec
|
|
57
|
+
assertApprovals(approvals)
|
|
58
|
+
return { approvals, config: deserializeConfig(config) }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export declare namespace fromRpc {
|
|
62
|
+
/** Error type for `fromRpc`. */
|
|
63
|
+
export type ErrorType =
|
|
64
|
+
| Hex.isEqual.ErrorType
|
|
65
|
+
| InvalidSimulationError
|
|
66
|
+
| MultisigConfig.assert.ErrorType
|
|
67
|
+
| Rlp.fromHex.ErrorType
|
|
68
|
+
| Rlp.toHex.ErrorType
|
|
69
|
+
| Errors.GlobalErrorType
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Converts a multisig simulation spec to its JSON-RPC representation.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts twoslash
|
|
77
|
+
* // @noErrors
|
|
78
|
+
* import { MultisigSimulation } from 'ox/tempo'
|
|
79
|
+
*
|
|
80
|
+
* const specRpc = MultisigSimulation.toRpc(spec)
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @param spec - Multisig simulation spec.
|
|
84
|
+
* @returns The JSON-RPC multisig simulation spec with encoded configurations.
|
|
85
|
+
*/
|
|
86
|
+
export function toRpc(spec: Spec): Rpc {
|
|
87
|
+
const { approvals, config } = spec
|
|
88
|
+
assertApprovals(approvals)
|
|
89
|
+
return {
|
|
90
|
+
approvals: approvals.map(({ keyData, keyType, owner }) => ({
|
|
91
|
+
...(keyData !== undefined ? { keyData: shimKeyData(keyData) } : {}),
|
|
92
|
+
...(keyType !== undefined ? { keyType } : {}),
|
|
93
|
+
owner,
|
|
94
|
+
})),
|
|
95
|
+
config: serializeConfig(config),
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export declare namespace toRpc {
|
|
100
|
+
/** Error type for `toRpc`. */
|
|
101
|
+
export type ErrorType =
|
|
102
|
+
| Hex.fromNumber.ErrorType
|
|
103
|
+
| InvalidSimulationError
|
|
104
|
+
| MultisigConfig.assert.ErrorType
|
|
105
|
+
| Rlp.fromHex.ErrorType
|
|
106
|
+
| Errors.GlobalErrorType
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** @internal */
|
|
110
|
+
function assertApprovals(approvals: readonly unknown[]) {
|
|
111
|
+
if (
|
|
112
|
+
approvals.some(
|
|
113
|
+
(approval) =>
|
|
114
|
+
typeof approval !== 'object' ||
|
|
115
|
+
approval === null ||
|
|
116
|
+
'spec' in approval ||
|
|
117
|
+
'type' in approval,
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
throw new InvalidSimulationError({
|
|
121
|
+
reason: 'only untagged primitive owner approvals are allowed',
|
|
122
|
+
})
|
|
123
|
+
if (approvals.length > MultisigConfig.maxSignatures)
|
|
124
|
+
throw new InvalidSimulationError({
|
|
125
|
+
reason: `approval count exceeds ${MultisigConfig.maxSignatures}`,
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** @internal */
|
|
130
|
+
function deserializeConfig(config: Hex.Hex): MultisigConfig.Config {
|
|
131
|
+
const tuple = Rlp.toHex(config)
|
|
132
|
+
if (!Array.isArray(tuple) || tuple.length !== 4)
|
|
133
|
+
throw new InvalidSimulationError({ reason: 'invalid config encoding' })
|
|
134
|
+
const [salt, version, threshold, owners] = tuple
|
|
135
|
+
if (
|
|
136
|
+
Array.isArray(salt) ||
|
|
137
|
+
Hex.size(salt) !== 32 ||
|
|
138
|
+
Array.isArray(version) ||
|
|
139
|
+
Hex.size(version) > 8 ||
|
|
140
|
+
(version !== '0x' && Hex.slice(version, 0, 1) === '0x00') ||
|
|
141
|
+
Array.isArray(threshold) ||
|
|
142
|
+
Hex.size(threshold) > 1 ||
|
|
143
|
+
!Array.isArray(owners) ||
|
|
144
|
+
owners.some(
|
|
145
|
+
(owner) =>
|
|
146
|
+
!Array.isArray(owner) ||
|
|
147
|
+
owner.length !== 2 ||
|
|
148
|
+
owner.some(Array.isArray) ||
|
|
149
|
+
!Address.validate(owner[0]) ||
|
|
150
|
+
Hex.size(owner[1] as Hex.Hex) > 1,
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
throw new InvalidSimulationError({ reason: 'invalid config encoding' })
|
|
154
|
+
const value = MultisigConfig.fromTuple(
|
|
155
|
+
tuple as unknown as MultisigConfig.Tuple,
|
|
156
|
+
)
|
|
157
|
+
MultisigConfig.assert(value)
|
|
158
|
+
if (!Hex.isEqual(config, serializeConfig(value)))
|
|
159
|
+
throw new InvalidSimulationError({ reason: 'noncanonical config encoding' })
|
|
160
|
+
return value
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** @internal */
|
|
164
|
+
function serializeConfig(config: MultisigConfig.Input): Hex.Hex {
|
|
165
|
+
return Rlp.fromHex(MultisigConfig.toTuple(config))
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Shims long key data into the length hint accepted by Tempo's gas estimator.
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
172
|
+
function shimKeyData(data: Hex.Hex): Hex.Hex {
|
|
173
|
+
const size = Hex.size(data)
|
|
174
|
+
if (size <= 4) return data
|
|
175
|
+
return Hex.fromNumber(size, { size: 2 })
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Thrown when a native multisig simulation spec is invalid. */
|
|
179
|
+
export class InvalidSimulationError extends Errors.BaseError {
|
|
180
|
+
override readonly name = 'MultisigSimulation.InvalidSimulationError'
|
|
181
|
+
constructor(options: InvalidSimulationError.Options) {
|
|
182
|
+
super(`Invalid multisig simulation: ${options.reason}.`)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export declare namespace InvalidSimulationError {
|
|
187
|
+
/** Error construction options. */
|
|
188
|
+
export type Options = {
|
|
189
|
+
/** Validation failure. */
|
|
190
|
+
reason: string
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
import type { Provider } from 'ox'
|
|
2
2
|
import type {
|
|
3
3
|
KeyAuthorization,
|
|
4
|
+
MultisigConfig,
|
|
4
5
|
MultisigOperation,
|
|
6
|
+
MultisigSimulation,
|
|
5
7
|
RpcSchemaTempo,
|
|
6
8
|
} from 'ox/tempo'
|
|
7
9
|
import { expectTypeOf, test } from 'vp/test'
|
|
10
|
+
import type * as Address from '../core/Address.js'
|
|
8
11
|
import type * as Hex from '../core/Hex.js'
|
|
9
12
|
|
|
10
13
|
declare const provider: Provider.Provider<{ schema: RpcSchemaTempo.Multisig }>
|
|
14
|
+
declare const tempoProvider: Provider.Provider<{
|
|
15
|
+
schema: RpcSchemaTempo.Tempo
|
|
16
|
+
}>
|
|
17
|
+
declare const address: Address.Address
|
|
11
18
|
declare const hash: Hex.Hex
|
|
12
19
|
declare const keyAuthorization: KeyAuthorization.Rpc
|
|
20
|
+
declare const multisigSimulation: MultisigSimulation.Rpc
|
|
13
21
|
declare const serializedTransaction: Hex.Hex
|
|
14
22
|
declare const signature: Hex.Hex
|
|
15
23
|
|
|
16
24
|
test('multisig provider methods', () => {
|
|
25
|
+
expectTypeOf(
|
|
26
|
+
provider.request({
|
|
27
|
+
method: 'multisig_approveKeyAuthorization',
|
|
28
|
+
params: [{ keyAuthorization }],
|
|
29
|
+
}),
|
|
30
|
+
).resolves.toEqualTypeOf<MultisigOperation.KeyAuthorizationRpc>()
|
|
31
|
+
|
|
32
|
+
expectTypeOf(
|
|
33
|
+
provider.request({
|
|
34
|
+
method: 'multisig_approveKeyAuthorization',
|
|
35
|
+
params: [{ hash, signature }],
|
|
36
|
+
}),
|
|
37
|
+
).resolves.toEqualTypeOf<MultisigOperation.KeyAuthorizationRpc>()
|
|
38
|
+
|
|
17
39
|
expectTypeOf(
|
|
18
40
|
provider.request({
|
|
19
41
|
method: 'multisig_approveRawTransaction',
|
|
@@ -35,17 +57,10 @@ test('multisig provider methods', () => {
|
|
|
35
57
|
|
|
36
58
|
expectTypeOf(
|
|
37
59
|
provider.request({
|
|
38
|
-
method: '
|
|
39
|
-
params: [{
|
|
60
|
+
method: 'multisig_getConfig',
|
|
61
|
+
params: [{ address }],
|
|
40
62
|
}),
|
|
41
|
-
).resolves.toEqualTypeOf<
|
|
42
|
-
|
|
43
|
-
expectTypeOf(
|
|
44
|
-
provider.request({
|
|
45
|
-
method: 'multisig_approveKeyAuthorization',
|
|
46
|
-
params: [{ hash, signature }],
|
|
47
|
-
}),
|
|
48
|
-
).resolves.toEqualTypeOf<MultisigOperation.KeyAuthorizationRpc>()
|
|
63
|
+
).resolves.toEqualTypeOf<MultisigConfig.Rpc | null>()
|
|
49
64
|
|
|
50
65
|
expectTypeOf(
|
|
51
66
|
provider.request({
|
|
@@ -54,3 +69,23 @@ test('multisig provider methods', () => {
|
|
|
54
69
|
}),
|
|
55
70
|
).resolves.toEqualTypeOf<MultisigOperation.Rpc | null>()
|
|
56
71
|
})
|
|
72
|
+
|
|
73
|
+
test('tempo simulation accepts multisig specs', () => {
|
|
74
|
+
void tempoProvider.request({
|
|
75
|
+
method: 'tempo_simulateV1',
|
|
76
|
+
params: [
|
|
77
|
+
{
|
|
78
|
+
blockStateCalls: [
|
|
79
|
+
{
|
|
80
|
+
calls: [
|
|
81
|
+
{
|
|
82
|
+
multisigSimulation,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
'latest',
|
|
89
|
+
],
|
|
90
|
+
})
|
|
91
|
+
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type * as Address from '../core/Address.js'
|
|
1
2
|
import type * as Block from '../core/Block.js'
|
|
2
3
|
import type * as BlockOverrides from '../core/BlockOverrides.js'
|
|
3
4
|
import type * as Hex from '../core/Hex.js'
|
|
@@ -5,6 +6,7 @@ import type * as Log from '../core/Log.js'
|
|
|
5
6
|
import type * as RpcSchema from '../core/RpcSchema.js'
|
|
6
7
|
import type * as StateOverrides from '../core/StateOverrides.js'
|
|
7
8
|
import type * as KeyAuthorization from './KeyAuthorization.js'
|
|
9
|
+
import type * as MultisigConfig from './MultisigConfig.js'
|
|
8
10
|
import type * as MultisigOperation from './MultisigOperation.js'
|
|
9
11
|
import type * as TransactionRequest from './TransactionRequest.js'
|
|
10
12
|
|
|
@@ -58,6 +60,16 @@ export type Tempo = RpcSchema.From<{
|
|
|
58
60
|
|
|
59
61
|
/** Union of all JSON-RPC methods for the `multisig_` namespace. */
|
|
60
62
|
export type Multisig = RpcSchema.From<
|
|
63
|
+
| {
|
|
64
|
+
Request: {
|
|
65
|
+
method: 'multisig_approveKeyAuthorization'
|
|
66
|
+
params: [
|
|
67
|
+
| { keyAuthorization: KeyAuthorization.Rpc }
|
|
68
|
+
| { hash: Hex.Hex; signature: Hex.Hex },
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
ReturnType: MultisigOperation.KeyAuthorizationRpc
|
|
72
|
+
}
|
|
61
73
|
| {
|
|
62
74
|
Request: {
|
|
63
75
|
method: 'multisig_approveRawTransaction'
|
|
@@ -74,13 +86,10 @@ export type Multisig = RpcSchema.From<
|
|
|
74
86
|
}
|
|
75
87
|
| {
|
|
76
88
|
Request: {
|
|
77
|
-
method: '
|
|
78
|
-
params: [
|
|
79
|
-
| { keyAuthorization: KeyAuthorization.Rpc }
|
|
80
|
-
| { hash: Hex.Hex; signature: Hex.Hex },
|
|
81
|
-
]
|
|
89
|
+
method: 'multisig_getConfig'
|
|
90
|
+
params: [{ address: Address.Address }]
|
|
82
91
|
}
|
|
83
|
-
ReturnType:
|
|
92
|
+
ReturnType: MultisigConfig.Rpc | null
|
|
84
93
|
}
|
|
85
94
|
| {
|
|
86
95
|
Request: {
|
|
@@ -1,114 +1,40 @@
|
|
|
1
1
|
import { expectTypeOf, test } from 'vp/test'
|
|
2
|
-
import * as
|
|
2
|
+
import type * as Hex from '../core/Hex.js'
|
|
3
3
|
import * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
r: '0x01',
|
|
15
|
-
s: '0x02',
|
|
16
|
-
yParity: 0,
|
|
5
|
+
const primitive = SignatureEnvelope.from({ r: '0x01', s: '0x02', yParity: 0 })
|
|
6
|
+
const envelope = SignatureEnvelope.from({
|
|
7
|
+
account: '0x2222222222222222222222222222222222222222',
|
|
8
|
+
config: {
|
|
9
|
+
threshold: 1,
|
|
10
|
+
version: 0n,
|
|
11
|
+
owners: [
|
|
12
|
+
{ owner: '0x1111111111111111111111111111111111111111', weight: 1 },
|
|
13
|
+
],
|
|
17
14
|
},
|
|
18
|
-
|
|
19
|
-
} as const satisfies SignatureEnvelope.Secp256k1
|
|
20
|
-
|
|
21
|
-
const config = MultisigConfig.from({
|
|
22
|
-
owners: [
|
|
23
|
-
{
|
|
24
|
-
owner: '0x1111111111111111111111111111111111111111',
|
|
25
|
-
weight: 1,
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
threshold: 1,
|
|
15
|
+
signatures: [primitive],
|
|
29
16
|
})
|
|
30
17
|
|
|
31
|
-
test('
|
|
18
|
+
test('preserves primitive and multisig RPC types', () => {
|
|
32
19
|
expectTypeOf(
|
|
33
|
-
SignatureEnvelope.toRpc(
|
|
20
|
+
SignatureEnvelope.toRpc(primitive),
|
|
34
21
|
).toEqualTypeOf<SignatureEnvelope.Secp256k1Rpc>()
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
test('MultisigRpc carries one complete witness shape', () => {
|
|
38
|
-
const rpc = {
|
|
39
|
-
account: '0x1111111111111111111111111111111111111111',
|
|
40
|
-
config: MultisigConfig.toRpc(config),
|
|
41
|
-
signatures: [signatureRpc],
|
|
42
|
-
} as const satisfies SignatureEnvelope.MultisigRpc
|
|
43
|
-
|
|
44
|
-
expectTypeOf(rpc.config).toMatchTypeOf<MultisigConfig.Rpc>()
|
|
45
|
-
expectTypeOf(rpc.signatures).toMatchTypeOf<
|
|
46
|
-
readonly SignatureEnvelope.SignatureEnvelopeRpc[]
|
|
47
|
-
>()
|
|
22
|
+
expectTypeOf(SignatureEnvelope.toRpc(envelope)).toEqualTypeOf<Hex.Hex>()
|
|
48
23
|
expectTypeOf<
|
|
49
|
-
SignatureEnvelope.GetType<typeof
|
|
24
|
+
SignatureEnvelope.GetType<typeof envelope>
|
|
50
25
|
>().toEqualTypeOf<'multisig'>()
|
|
26
|
+
expectTypeOf(envelope).toMatchTypeOf<SignatureEnvelope.Multisig>()
|
|
51
27
|
})
|
|
52
28
|
|
|
53
|
-
test('
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// @ts-expect-error Current configurations require an explicit account.
|
|
65
|
-
SignatureEnvelope.from({
|
|
66
|
-
config: { ...config, version: 1 },
|
|
67
|
-
signatures: [signature],
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
const multisig = SignatureEnvelope.from({
|
|
71
|
-
account: '0x2222222222222222222222222222222222222222',
|
|
72
|
-
config: { ...config, version: 1 },
|
|
73
|
-
signatures: [signature],
|
|
74
|
-
})
|
|
75
|
-
expectTypeOf(multisig).toMatchTypeOf<SignatureEnvelope.Multisig>()
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
test('MultisigRpc rejects old witness shapes', () => {
|
|
79
|
-
const accountOnly = {
|
|
80
|
-
account: '0x1111111111111111111111111111111111111111',
|
|
81
|
-
signatures: [signatureRpc],
|
|
82
|
-
} as const
|
|
83
|
-
// @ts-expect-error Multisig RPC signatures require config.
|
|
84
|
-
const accountOnlyRpc: SignatureEnvelope.MultisigRpc = accountOnly
|
|
85
|
-
|
|
86
|
-
const init = {
|
|
87
|
-
init: config,
|
|
88
|
-
signatures: [signatureRpc],
|
|
89
|
-
} as const
|
|
90
|
-
// @ts-expect-error Multisig RPC signatures no longer accept init.
|
|
91
|
-
const initRpc: SignatureEnvelope.MultisigRpc = init
|
|
92
|
-
|
|
93
|
-
const serialized = {
|
|
94
|
-
account: '0x1111111111111111111111111111111111111111',
|
|
95
|
-
config: MultisigConfig.toRpc(config),
|
|
96
|
-
signatures: ['0x1234'],
|
|
97
|
-
} as const
|
|
98
|
-
// @ts-expect-error Owner approvals use structured RPC envelopes.
|
|
99
|
-
const serializedRpc: SignatureEnvelope.MultisigRpc = serialized
|
|
100
|
-
|
|
101
|
-
const tagged = {
|
|
102
|
-
account: '0x1111111111111111111111111111111111111111',
|
|
103
|
-
config: MultisigConfig.toRpc(config),
|
|
104
|
-
signatures: [signatureRpc],
|
|
105
|
-
type: 'multisig',
|
|
106
|
-
} as const
|
|
107
|
-
// @ts-expect-error Multisig RPC signatures are untagged.
|
|
108
|
-
const taggedRpc: SignatureEnvelope.MultisigRpc = tagged
|
|
109
|
-
|
|
110
|
-
expectTypeOf(accountOnlyRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
111
|
-
expectTypeOf(initRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
112
|
-
expectTypeOf(serializedRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
113
|
-
expectTypeOf(taggedRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
29
|
+
test('requires config and primitive approvals', () => {
|
|
30
|
+
// @ts-expect-error Every multisig signature carries its current config.
|
|
31
|
+
SignatureEnvelope.from({ account: envelope.account, signatures: [primitive] })
|
|
32
|
+
// @ts-expect-error Multisig owners cannot recursively approve with multisigs.
|
|
33
|
+
SignatureEnvelope.from({ ...envelope, signatures: [envelope] })
|
|
34
|
+
// @ts-expect-error Multisig RPC signatures are hex-encoded RLP.
|
|
35
|
+
const rpc: SignatureEnvelope.MultisigRpc = {
|
|
36
|
+
account: envelope.account,
|
|
37
|
+
signatures: [],
|
|
38
|
+
}
|
|
39
|
+
expectTypeOf(rpc).toEqualTypeOf<Hex.Hex>()
|
|
114
40
|
})
|