ox 0.14.39 → 0.14.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/_cjs/tempo/MultisigOperation.js +30 -45
- package/_cjs/tempo/MultisigOperation.js.map +1 -1
- package/_cjs/tempo/MultisigWitness.js +92 -0
- package/_cjs/tempo/MultisigWitness.js.map +1 -0
- package/_cjs/tempo/SignatureEnvelope.js +5 -2
- package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
- package/_cjs/tempo/TransactionRequest.js +7 -1
- package/_cjs/tempo/TransactionRequest.js.map +1 -1
- package/_cjs/tempo/index.js +2 -1
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/tempo/MultisigOperation.js +31 -48
- package/_esm/tempo/MultisigOperation.js.map +1 -1
- package/_esm/tempo/MultisigWitness.js +123 -0
- package/_esm/tempo/MultisigWitness.js.map +1 -0
- package/_esm/tempo/SignatureEnvelope.js +5 -2
- package/_esm/tempo/SignatureEnvelope.js.map +1 -1
- package/_esm/tempo/TransactionRequest.js +7 -1
- package/_esm/tempo/TransactionRequest.js.map +1 -1
- package/_esm/tempo/index.js +9 -0
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/tempo/MultisigOperation.d.ts +4 -25
- package/_types/tempo/MultisigOperation.d.ts.map +1 -1
- package/_types/tempo/MultisigWitness.d.ts +106 -0
- package/_types/tempo/MultisigWitness.d.ts.map +1 -0
- package/_types/tempo/SignatureEnvelope.d.ts +3 -3
- package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/_types/tempo/TransactionRequest.d.ts +6 -3
- package/_types/tempo/TransactionRequest.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +9 -0
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/package.json +16 -1
- package/tempo/KeyAuthorization.test-d.ts +1 -1
- package/tempo/MultisigOperation.test-d.ts +0 -6
- package/tempo/MultisigOperation.test.ts +196 -145
- package/tempo/MultisigOperation.ts +40 -83
- package/tempo/MultisigWitness/package.json +6 -0
- package/tempo/MultisigWitness.test-d/package.json +6 -0
- package/tempo/MultisigWitness.test-d.ts +42 -0
- package/tempo/MultisigWitness.test.ts +289 -0
- package/tempo/MultisigWitness.ts +210 -0
- package/tempo/RpcSchemaTempo.test-d.ts +25 -0
- package/tempo/SignatureEnvelope.test-d.ts +4 -4
- package/tempo/SignatureEnvelope.test.ts +2 -2
- package/tempo/SignatureEnvelope.ts +9 -5
- package/tempo/TransactionRequest.test-d/package.json +6 -0
- package/tempo/TransactionRequest.test-d.ts +24 -0
- package/tempo/TransactionRequest.test.ts +102 -1
- package/tempo/TransactionRequest.ts +12 -2
- package/tempo/index.ts +9 -0
- package/version.ts +1 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type * 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 MultisigConfig from './MultisigConfig.js'
|
|
6
|
+
import type * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
7
|
+
|
|
8
|
+
/** Native multisig owner approval used for RPC simulation. */
|
|
9
|
+
export type Approval<versionType = bigint> =
|
|
10
|
+
| NestedApproval<versionType>
|
|
11
|
+
| PrimitiveApproval
|
|
12
|
+
|
|
13
|
+
/** Native multisig witness used to construct an RPC simulation signature. */
|
|
14
|
+
export type MultisigWitness<versionType = bigint> = Compute<{
|
|
15
|
+
/** Account authorized by this witness. */
|
|
16
|
+
account: Address.Address
|
|
17
|
+
/** Owner approvals to model. */
|
|
18
|
+
approvals: readonly Approval<versionType>[]
|
|
19
|
+
/** Complete applicable configuration. */
|
|
20
|
+
config: MultisigConfig.Config<versionType>
|
|
21
|
+
}>
|
|
22
|
+
|
|
23
|
+
/** Nested native multisig owner approval used for RPC simulation. */
|
|
24
|
+
export type NestedApproval<versionType = bigint> = {
|
|
25
|
+
/** Approval type. */
|
|
26
|
+
type: 'multisig'
|
|
27
|
+
/** Depth-2 multisig witness. */
|
|
28
|
+
witness: NestedWitness<versionType>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Primitive approval in a depth-2 multisig simulation witness. */
|
|
32
|
+
export type NestedPrimitiveApproval = {
|
|
33
|
+
/** Optional signature-specific gas-estimation data. */
|
|
34
|
+
keyData?: Hex.Hex | undefined
|
|
35
|
+
/** Signature type to model. Omission uses a maximum-size WebAuthn signature. */
|
|
36
|
+
keyType?: SignatureEnvelope.Type | undefined
|
|
37
|
+
/** Configured owner address. */
|
|
38
|
+
owner: Address.Address
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Depth-2 native multisig witness used for RPC simulation. */
|
|
42
|
+
export type NestedWitness<versionType = bigint> = {
|
|
43
|
+
/** Nested multisig account. */
|
|
44
|
+
account: Address.Address
|
|
45
|
+
/** Primitive owner approvals to model. */
|
|
46
|
+
approvals: readonly NestedPrimitiveApproval[]
|
|
47
|
+
/** Complete applicable configuration. */
|
|
48
|
+
config: MultisigConfig.Config<versionType>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Primitive owner approval used for RPC simulation. */
|
|
52
|
+
export type PrimitiveApproval = {
|
|
53
|
+
/** Optional signature-specific gas-estimation data. */
|
|
54
|
+
keyData?: Hex.Hex | undefined
|
|
55
|
+
/** Signature type to model. Omission uses a maximum-size WebAuthn signature. */
|
|
56
|
+
keyType?: SignatureEnvelope.Type | undefined
|
|
57
|
+
/** Configured owner address. */
|
|
58
|
+
owner: Address.Address
|
|
59
|
+
/** Approval type. */
|
|
60
|
+
type: 'primitive'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** JSON-RPC representation of a native multisig simulation witness. */
|
|
64
|
+
export type Rpc = MultisigWitness<number>
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Converts a JSON-RPC multisig witness to its domain representation.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts twoslash
|
|
71
|
+
* // @noErrors
|
|
72
|
+
* import { MultisigWitness } from 'ox/tempo'
|
|
73
|
+
*
|
|
74
|
+
* const witness = MultisigWitness.fromRpc(witnessRpc)
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @param witness - JSON-RPC multisig witness.
|
|
78
|
+
* @returns The multisig witness with bigint configuration versions.
|
|
79
|
+
*/
|
|
80
|
+
export function fromRpc(witness: Rpc): MultisigWitness {
|
|
81
|
+
const { account, approvals, config } = witness
|
|
82
|
+
assertApprovalCount(approvals)
|
|
83
|
+
return {
|
|
84
|
+
account,
|
|
85
|
+
approvals: approvals.map((approval) => {
|
|
86
|
+
if (approval.type === 'primitive') return approval
|
|
87
|
+
assertApprovalCount(approval.witness.approvals)
|
|
88
|
+
return {
|
|
89
|
+
type: 'multisig',
|
|
90
|
+
witness: {
|
|
91
|
+
account: approval.witness.account,
|
|
92
|
+
approvals: approval.witness.approvals,
|
|
93
|
+
config: MultisigConfig.from(approval.witness.config),
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
}),
|
|
97
|
+
config: MultisigConfig.from(config),
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export declare namespace fromRpc {
|
|
102
|
+
/** Error type for `fromRpc`. */
|
|
103
|
+
export type ErrorType =
|
|
104
|
+
| InvalidWitnessError
|
|
105
|
+
| MultisigConfig.assert.ErrorType
|
|
106
|
+
| Errors.GlobalErrorType
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Converts a multisig witness to its JSON-RPC representation.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts twoslash
|
|
114
|
+
* // @noErrors
|
|
115
|
+
* import { MultisigWitness } from 'ox/tempo'
|
|
116
|
+
*
|
|
117
|
+
* const witnessRpc = MultisigWitness.toRpc(witness)
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @param witness - Multisig witness.
|
|
121
|
+
* @returns The JSON-RPC multisig witness with numeric configuration versions.
|
|
122
|
+
*/
|
|
123
|
+
export function toRpc(witness: MultisigWitness): Rpc {
|
|
124
|
+
const { account, approvals, config } = witness
|
|
125
|
+
assertApprovalCount(approvals)
|
|
126
|
+
return {
|
|
127
|
+
account,
|
|
128
|
+
approvals: approvals.map((approval) => {
|
|
129
|
+
if (approval.type === 'primitive')
|
|
130
|
+
return {
|
|
131
|
+
...approval,
|
|
132
|
+
...(typeof approval.keyData !== 'undefined'
|
|
133
|
+
? { keyData: shimKeyData(approval.keyData) }
|
|
134
|
+
: {}),
|
|
135
|
+
}
|
|
136
|
+
assertApprovalCount(approval.witness.approvals)
|
|
137
|
+
return {
|
|
138
|
+
type: 'multisig',
|
|
139
|
+
witness: {
|
|
140
|
+
account: approval.witness.account,
|
|
141
|
+
approvals: approval.witness.approvals.map((approval) => ({
|
|
142
|
+
...approval,
|
|
143
|
+
...(typeof approval.keyData !== 'undefined'
|
|
144
|
+
? { keyData: shimKeyData(approval.keyData) }
|
|
145
|
+
: {}),
|
|
146
|
+
})),
|
|
147
|
+
config: configToRpc(approval.witness.config),
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
}),
|
|
151
|
+
config: configToRpc(config),
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export declare namespace toRpc {
|
|
156
|
+
/** Error type for `toRpc`. */
|
|
157
|
+
export type ErrorType =
|
|
158
|
+
| Hex.fromNumber.ErrorType
|
|
159
|
+
| Hex.toNumber.ErrorType
|
|
160
|
+
| InvalidWitnessError
|
|
161
|
+
| MultisigConfig.assert.ErrorType
|
|
162
|
+
| Errors.GlobalErrorType
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** @internal */
|
|
166
|
+
function assertApprovalCount(approvals: readonly unknown[]) {
|
|
167
|
+
if (approvals.length > MultisigConfig.maxSignatures)
|
|
168
|
+
throw new InvalidWitnessError({
|
|
169
|
+
reason: `approval count exceeds ${MultisigConfig.maxSignatures}`,
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** @internal */
|
|
174
|
+
function configToRpc(
|
|
175
|
+
config: MultisigConfig.Config,
|
|
176
|
+
): MultisigConfig.Config<number> {
|
|
177
|
+
const value = MultisigConfig.from(config)
|
|
178
|
+
return {
|
|
179
|
+
...value,
|
|
180
|
+
version: Hex.toNumber(Hex.fromNumber(Number(value.version))),
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Shims key data longer than 4 bytes into a 2-byte big-endian length hint.
|
|
186
|
+
* The node's gas estimator only accepts 1, 2, or 4-byte key data as a
|
|
187
|
+
* signature-size hint; anything else silently falls back to the default.
|
|
188
|
+
* @internal
|
|
189
|
+
*/
|
|
190
|
+
function shimKeyData(data: Hex.Hex): Hex.Hex {
|
|
191
|
+
const size = Hex.size(data)
|
|
192
|
+
if (size <= 4) return data
|
|
193
|
+
return Hex.fromNumber(size, { size: 2 })
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Thrown when a native multisig witness is invalid. */
|
|
197
|
+
export class InvalidWitnessError extends Errors.BaseError {
|
|
198
|
+
override readonly name = 'MultisigWitness.InvalidWitnessError'
|
|
199
|
+
constructor(options: InvalidWitnessError.Options) {
|
|
200
|
+
super(`Invalid multisig witness: ${options.reason}.`)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export declare namespace InvalidWitnessError {
|
|
205
|
+
/** Error construction options. */
|
|
206
|
+
export type Options = {
|
|
207
|
+
/** Validation failure. */
|
|
208
|
+
reason: string
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -2,14 +2,19 @@ import type { Provider } from 'ox'
|
|
|
2
2
|
import type {
|
|
3
3
|
KeyAuthorization,
|
|
4
4
|
MultisigOperation,
|
|
5
|
+
MultisigWitness,
|
|
5
6
|
RpcSchemaTempo,
|
|
6
7
|
} from 'ox/tempo'
|
|
7
8
|
import { expectTypeOf, test } from 'vitest'
|
|
8
9
|
import type * as Hex from '../core/Hex.js'
|
|
9
10
|
|
|
10
11
|
declare const provider: Provider.Provider<{ schema: RpcSchemaTempo.Multisig }>
|
|
12
|
+
declare const tempoProvider: Provider.Provider<{
|
|
13
|
+
schema: RpcSchemaTempo.Tempo
|
|
14
|
+
}>
|
|
11
15
|
declare const hash: Hex.Hex
|
|
12
16
|
declare const keyAuthorization: KeyAuthorization.Rpc
|
|
17
|
+
declare const multisigWitness: MultisigWitness.Rpc
|
|
13
18
|
declare const serializedTransaction: Hex.Hex
|
|
14
19
|
declare const signature: Hex.Hex
|
|
15
20
|
|
|
@@ -54,3 +59,23 @@ test('multisig provider methods', () => {
|
|
|
54
59
|
}),
|
|
55
60
|
).resolves.toEqualTypeOf<MultisigOperation.Rpc | null>()
|
|
56
61
|
})
|
|
62
|
+
|
|
63
|
+
test('tempo simulation accepts multisig witnesses', () => {
|
|
64
|
+
tempoProvider.request({
|
|
65
|
+
method: 'tempo_simulateV1',
|
|
66
|
+
params: [
|
|
67
|
+
{
|
|
68
|
+
blockStateCalls: [
|
|
69
|
+
{
|
|
70
|
+
calls: [
|
|
71
|
+
{
|
|
72
|
+
multisigWitness,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
'latest',
|
|
79
|
+
],
|
|
80
|
+
})
|
|
81
|
+
})
|
|
@@ -37,11 +37,11 @@ test('toRpc preserves the signature type', () => {
|
|
|
37
37
|
test('MultisigRpc carries one complete witness shape', () => {
|
|
38
38
|
const rpc = {
|
|
39
39
|
account: '0x1111111111111111111111111111111111111111',
|
|
40
|
-
config:
|
|
40
|
+
config: { ...config, version: 0 },
|
|
41
41
|
signatures: [signatureRpc],
|
|
42
42
|
} as const satisfies SignatureEnvelope.MultisigRpc
|
|
43
43
|
|
|
44
|
-
expectTypeOf(rpc.config).toMatchTypeOf<MultisigConfig.
|
|
44
|
+
expectTypeOf(rpc.config).toMatchTypeOf<MultisigConfig.Config<number>>()
|
|
45
45
|
expectTypeOf(rpc.signatures).toMatchTypeOf<
|
|
46
46
|
readonly SignatureEnvelope.SignatureEnvelopeRpc[]
|
|
47
47
|
>()
|
|
@@ -92,7 +92,7 @@ test('MultisigRpc rejects old witness shapes', () => {
|
|
|
92
92
|
|
|
93
93
|
const serialized = {
|
|
94
94
|
account: '0x1111111111111111111111111111111111111111',
|
|
95
|
-
config:
|
|
95
|
+
config: { ...config, version: 0 },
|
|
96
96
|
signatures: ['0x1234'],
|
|
97
97
|
} as const
|
|
98
98
|
// @ts-expect-error Owner approvals use structured RPC envelopes.
|
|
@@ -100,7 +100,7 @@ test('MultisigRpc rejects old witness shapes', () => {
|
|
|
100
100
|
|
|
101
101
|
const tagged = {
|
|
102
102
|
account: '0x1111111111111111111111111111111111111111',
|
|
103
|
-
config:
|
|
103
|
+
config: { ...config, version: 0 },
|
|
104
104
|
signatures: [signatureRpc],
|
|
105
105
|
type: 'multisig',
|
|
106
106
|
} as const
|
|
@@ -3035,7 +3035,7 @@ describe('multisig', () => {
|
|
|
3035
3035
|
],
|
|
3036
3036
|
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
3037
3037
|
"threshold": 1,
|
|
3038
|
-
"version":
|
|
3038
|
+
"version": 1,
|
|
3039
3039
|
},
|
|
3040
3040
|
"signatures": [
|
|
3041
3041
|
{
|
|
@@ -3057,7 +3057,7 @@ describe('multisig', () => {
|
|
|
3057
3057
|
],
|
|
3058
3058
|
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
3059
3059
|
"threshold": 1,
|
|
3060
|
-
"version":
|
|
3060
|
+
"version": 0,
|
|
3061
3061
|
},
|
|
3062
3062
|
"signatures": [
|
|
3063
3063
|
{
|
|
@@ -245,7 +245,7 @@ export type MultisigRpc = {
|
|
|
245
245
|
/** Native multisig account address. */
|
|
246
246
|
account: Address.Address
|
|
247
247
|
/** Complete applicable multisig configuration witness. */
|
|
248
|
-
config: MultisigConfig.
|
|
248
|
+
config: MultisigConfig.Config<number>
|
|
249
249
|
/** Structured owner approvals. */
|
|
250
250
|
signatures: readonly SignatureEnvelopeRpc[]
|
|
251
251
|
/** Multisig RPC signatures are untagged. */
|
|
@@ -1229,7 +1229,7 @@ export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
|
|
|
1229
1229
|
const multisig = envelope as MultisigRpc
|
|
1230
1230
|
const result = {
|
|
1231
1231
|
account: multisig.account,
|
|
1232
|
-
config: MultisigConfig.
|
|
1232
|
+
config: MultisigConfig.from(multisig.config),
|
|
1233
1233
|
signatures: multisig.signatures.map((signature) => fromRpc(signature)),
|
|
1234
1234
|
type: 'multisig',
|
|
1235
1235
|
} satisfies Multisig
|
|
@@ -1245,7 +1245,7 @@ export declare namespace fromRpc {
|
|
|
1245
1245
|
| assert.ErrorType
|
|
1246
1246
|
| CoercionError
|
|
1247
1247
|
| InvalidSerializedError
|
|
1248
|
-
| MultisigConfig.
|
|
1248
|
+
| MultisigConfig.assert.ErrorType
|
|
1249
1249
|
| Signature.fromRpc.ErrorType
|
|
1250
1250
|
| Errors.GlobalErrorType
|
|
1251
1251
|
}
|
|
@@ -1614,7 +1614,10 @@ export function toRpc<const envelope extends toRpc.Input>(
|
|
|
1614
1614
|
assert(multisig)
|
|
1615
1615
|
return {
|
|
1616
1616
|
account: multisig.account,
|
|
1617
|
-
config:
|
|
1617
|
+
config: {
|
|
1618
|
+
...multisig.config,
|
|
1619
|
+
version: Hex.toNumber(Hex.fromNumber(multisig.config.version)),
|
|
1620
|
+
},
|
|
1618
1621
|
signatures: multisig.signatures.map((signature) => toRpc(signature)),
|
|
1619
1622
|
} as never
|
|
1620
1623
|
}
|
|
@@ -1643,7 +1646,8 @@ export declare namespace toRpc {
|
|
|
1643
1646
|
type ErrorType =
|
|
1644
1647
|
| assert.ErrorType
|
|
1645
1648
|
| CoercionError
|
|
1646
|
-
|
|
|
1649
|
+
| Hex.fromNumber.ErrorType
|
|
1650
|
+
| Hex.toNumber.ErrorType
|
|
1647
1651
|
| Signature.toRpc.ErrorType
|
|
1648
1652
|
| Errors.GlobalErrorType
|
|
1649
1653
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { expectTypeOf, test } from 'vitest'
|
|
2
|
+
import type * as MultisigWitness from './MultisigWitness.js'
|
|
3
|
+
import type * as TransactionRequest from './TransactionRequest.js'
|
|
4
|
+
|
|
5
|
+
declare const request: TransactionRequest.TransactionRequest
|
|
6
|
+
declare const rpc: TransactionRequest.Rpc
|
|
7
|
+
|
|
8
|
+
test('transaction requests use domain multisig witnesses', () => {
|
|
9
|
+
expectTypeOf(request.multisigWitness?.config.version).toEqualTypeOf<
|
|
10
|
+
bigint | undefined
|
|
11
|
+
>()
|
|
12
|
+
|
|
13
|
+
const approval = request.multisigWitness?.approvals[0]
|
|
14
|
+
if (approval?.type === 'multisig')
|
|
15
|
+
expectTypeOf(approval.witness.approvals[0]?.keyType).toEqualTypeOf<
|
|
16
|
+
MultisigWitness.NestedPrimitiveApproval['keyType']
|
|
17
|
+
>()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('RPC requests use numeric multisig config versions', () => {
|
|
21
|
+
expectTypeOf(rpc.multisigWitness?.config.version).toEqualTypeOf<
|
|
22
|
+
number | undefined
|
|
23
|
+
>()
|
|
24
|
+
})
|
|
@@ -1,6 +1,74 @@
|
|
|
1
|
-
import { TransactionRequest } from 'ox/tempo'
|
|
1
|
+
import { type MultisigWitness, TransactionRequest } from 'ox/tempo'
|
|
2
2
|
import { describe, expect, test } from 'vitest'
|
|
3
3
|
|
|
4
|
+
const multisigWitnessRpc = {
|
|
5
|
+
account: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
6
|
+
approvals: [
|
|
7
|
+
{
|
|
8
|
+
keyType: 'secp256k1',
|
|
9
|
+
owner: '0x1111111111111111111111111111111111111111',
|
|
10
|
+
type: 'primitive',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
type: 'multisig',
|
|
14
|
+
witness: {
|
|
15
|
+
account: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
|
16
|
+
approvals: [
|
|
17
|
+
{
|
|
18
|
+
keyData: '0x0578',
|
|
19
|
+
keyType: 'webAuthn',
|
|
20
|
+
owner: '0x2222222222222222222222222222222222222222',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
config: {
|
|
24
|
+
owners: [
|
|
25
|
+
{
|
|
26
|
+
owner: '0x2222222222222222222222222222222222222222',
|
|
27
|
+
weight: 1,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
salt: `0x${'22'.repeat(32)}`,
|
|
31
|
+
threshold: 1,
|
|
32
|
+
version: 1,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
config: {
|
|
38
|
+
owners: [
|
|
39
|
+
{
|
|
40
|
+
owner: '0x1111111111111111111111111111111111111111',
|
|
41
|
+
weight: 1,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
owner: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
|
45
|
+
weight: 1,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
salt: `0x${'11'.repeat(32)}`,
|
|
49
|
+
threshold: 2,
|
|
50
|
+
version: 0,
|
|
51
|
+
},
|
|
52
|
+
} as const satisfies MultisigWitness.Rpc
|
|
53
|
+
|
|
54
|
+
const multisigWitness = {
|
|
55
|
+
...multisigWitnessRpc,
|
|
56
|
+
approvals: [
|
|
57
|
+
multisigWitnessRpc.approvals[0],
|
|
58
|
+
{
|
|
59
|
+
...multisigWitnessRpc.approvals[1],
|
|
60
|
+
witness: {
|
|
61
|
+
...multisigWitnessRpc.approvals[1].witness,
|
|
62
|
+
config: {
|
|
63
|
+
...multisigWitnessRpc.approvals[1].witness.config,
|
|
64
|
+
version: 1n,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
config: { ...multisigWitnessRpc.config, version: 0n },
|
|
70
|
+
} as const satisfies MultisigWitness.MultisigWitness
|
|
71
|
+
|
|
4
72
|
describe('fromRpc', () => {
|
|
5
73
|
test('default', () => {
|
|
6
74
|
const request = TransactionRequest.fromRpc({
|
|
@@ -69,6 +137,21 @@ describe('fromRpc', () => {
|
|
|
69
137
|
expect(request.nonceKey).toBe(255n)
|
|
70
138
|
})
|
|
71
139
|
|
|
140
|
+
test('behavior: multisig witness', () => {
|
|
141
|
+
const request = TransactionRequest.fromRpc({
|
|
142
|
+
from: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
143
|
+
multisigWitness: multisigWitnessRpc,
|
|
144
|
+
type: '0x76',
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
expect(request.multisigWitness?.config.version).toBe(0n)
|
|
148
|
+
const nested = request.multisigWitness?.approvals[1]
|
|
149
|
+
expect(nested?.type).toBe('multisig')
|
|
150
|
+
if (nested?.type !== 'multisig') throw new Error('expected multisig')
|
|
151
|
+
expect(nested.witness.config.version).toBe(1n)
|
|
152
|
+
expect(nested.witness.approvals[0]?.keyType).toBe('webAuthn')
|
|
153
|
+
})
|
|
154
|
+
|
|
72
155
|
test('behavior: empty', () => {
|
|
73
156
|
const request = TransactionRequest.fromRpc({})
|
|
74
157
|
expect(request).toMatchInlineSnapshot('{}')
|
|
@@ -122,6 +205,20 @@ describe('toRpc', () => {
|
|
|
122
205
|
}
|
|
123
206
|
`)
|
|
124
207
|
})
|
|
208
|
+
|
|
209
|
+
test('behavior: multisig witness', () => {
|
|
210
|
+
const request = TransactionRequest.toRpc({
|
|
211
|
+
from: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
212
|
+
multisigWitness,
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
expect(request.multisigWitness?.config.version).toBe(0)
|
|
216
|
+
const nested = request.multisigWitness?.approvals[1]
|
|
217
|
+
expect(nested?.type).toBe('multisig')
|
|
218
|
+
if (nested?.type !== 'multisig') throw new Error('expected multisig')
|
|
219
|
+
expect(nested.witness.config.version).toBe(1)
|
|
220
|
+
expect(request.type).toBe('0x76')
|
|
221
|
+
})
|
|
125
222
|
})
|
|
126
223
|
|
|
127
224
|
describe('roundtrip', () => {
|
|
@@ -144,6 +241,7 @@ describe('roundtrip', () => {
|
|
|
144
241
|
nonceKey: 255n,
|
|
145
242
|
gas: 100000n,
|
|
146
243
|
maxFeePerGas: 1000000000n,
|
|
244
|
+
multisigWitness,
|
|
147
245
|
}
|
|
148
246
|
|
|
149
247
|
const rpc = TransactionRequest.toRpc(original)
|
|
@@ -164,6 +262,7 @@ describe('roundtrip', () => {
|
|
|
164
262
|
expect(converted.nonceKey).toBe(original.nonceKey)
|
|
165
263
|
expect(converted.gas).toBe(original.gas)
|
|
166
264
|
expect(converted.maxFeePerGas).toBe(original.maxFeePerGas)
|
|
265
|
+
expect(converted.multisigWitness).toEqual(original.multisigWitness)
|
|
167
266
|
expect(converted.type).toBe('tempo')
|
|
168
267
|
})
|
|
169
268
|
|
|
@@ -181,6 +280,7 @@ describe('roundtrip', () => {
|
|
|
181
280
|
validAfter: '0x32',
|
|
182
281
|
nonceKey: '0xff',
|
|
183
282
|
gas: '0x186a0',
|
|
283
|
+
multisigWitness: multisigWitnessRpc,
|
|
184
284
|
type: '0x76',
|
|
185
285
|
}
|
|
186
286
|
|
|
@@ -193,6 +293,7 @@ describe('roundtrip', () => {
|
|
|
193
293
|
expect(rpc.validAfter).toBe(original.validAfter)
|
|
194
294
|
expect(rpc.nonceKey).toBe(original.nonceKey)
|
|
195
295
|
expect(rpc.gas).toBe(original.gas)
|
|
296
|
+
expect(rpc.multisigWitness).toEqual(original.multisigWitness)
|
|
196
297
|
expect(rpc.type).toBe('0x76')
|
|
197
298
|
})
|
|
198
299
|
})
|
|
@@ -4,6 +4,7 @@ import type { Compute } from '../core/internal/types.js'
|
|
|
4
4
|
import * as ox_TransactionRequest from '../core/TransactionRequest.js'
|
|
5
5
|
import * as AuthorizationTempo from './AuthorizationTempo.js'
|
|
6
6
|
import * as KeyAuthorization from './KeyAuthorization.js'
|
|
7
|
+
import * as MultisigWitness from './MultisigWitness.js'
|
|
7
8
|
import * as TempoAddress from './TempoAddress.js'
|
|
8
9
|
import * as TokenId from './TokenId.js'
|
|
9
10
|
import * as Transaction from './Transaction.js'
|
|
@@ -38,6 +39,7 @@ export type TransactionRequest<
|
|
|
38
39
|
keyType?: KeyType | undefined
|
|
39
40
|
feePayer?: boolean | undefined
|
|
40
41
|
feeToken?: TokenId.TokenIdOrAddress<addressType> | undefined
|
|
42
|
+
multisigWitness?: MultisigWitness.MultisigWitness<bigintType> | undefined
|
|
41
43
|
nonceKey?: 'random' | bigintType | undefined
|
|
42
44
|
validBefore?: numberType | undefined
|
|
43
45
|
validAfter?: numberType | undefined
|
|
@@ -47,11 +49,12 @@ export type TransactionRequest<
|
|
|
47
49
|
/** RPC representation of a {@link ox#TransactionRequest.TransactionRequest}. */
|
|
48
50
|
export type Rpc = Omit<
|
|
49
51
|
TransactionRequest<Hex.Hex, Hex.Hex, string, Hex.Hex>,
|
|
50
|
-
'authorizationList' | 'feeToken' | 'keyAuthorization'
|
|
52
|
+
'authorizationList' | 'feeToken' | 'keyAuthorization' | 'multisigWitness'
|
|
51
53
|
> & {
|
|
52
54
|
authorizationList?: AuthorizationTempo.ListRpc | undefined
|
|
53
55
|
feeToken?: Hex.Hex | undefined
|
|
54
56
|
keyAuthorization?: KeyAuthorization.Rpc | undefined
|
|
57
|
+
multisigWitness?: MultisigWitness.Rpc | undefined
|
|
55
58
|
nonceKey?: Hex.Hex | undefined
|
|
56
59
|
}
|
|
57
60
|
|
|
@@ -76,7 +79,7 @@ export type Rpc = Omit<
|
|
|
76
79
|
* @returns A transaction request.
|
|
77
80
|
*/
|
|
78
81
|
export function fromRpc(request: Rpc): TransactionRequest {
|
|
79
|
-
const { authorizationList: _, ...rest } = request
|
|
82
|
+
const { authorizationList: _, multisigWitness: __, ...rest } = request
|
|
80
83
|
const request_ = ox_TransactionRequest.fromRpc(
|
|
81
84
|
rest as any,
|
|
82
85
|
) as TransactionRequest
|
|
@@ -107,6 +110,8 @@ export function fromRpc(request: Rpc): TransactionRequest {
|
|
|
107
110
|
request_.keyAuthorization = KeyAuthorization.fromRpc(
|
|
108
111
|
request.keyAuthorization,
|
|
109
112
|
)
|
|
113
|
+
if (request.multisigWitness)
|
|
114
|
+
request_.multisigWitness = MultisigWitness.fromRpc(request.multisigWitness)
|
|
110
115
|
if (typeof request.validBefore !== 'undefined')
|
|
111
116
|
request_.validBefore = Hex.toNumber(request.validBefore as Hex.Hex)
|
|
112
117
|
if (typeof request.validAfter !== 'undefined')
|
|
@@ -120,6 +125,7 @@ export function fromRpc(request: Rpc): TransactionRequest {
|
|
|
120
125
|
export declare namespace fromRpc {
|
|
121
126
|
export type ErrorType =
|
|
122
127
|
| AuthorizationTempo.fromRpcList.ErrorType
|
|
128
|
+
| MultisigWitness.fromRpc.ErrorType
|
|
123
129
|
| Hex.toNumber.ErrorType
|
|
124
130
|
| Hex.toBigInt.ErrorType
|
|
125
131
|
| Errors.GlobalErrorType
|
|
@@ -204,6 +210,8 @@ export function toRpc(request: TransactionRequest): Rpc {
|
|
|
204
210
|
request_rpc.keyAuthorization = KeyAuthorization.toRpc(
|
|
205
211
|
request.keyAuthorization,
|
|
206
212
|
)
|
|
213
|
+
if (request.multisigWitness)
|
|
214
|
+
request_rpc.multisigWitness = MultisigWitness.toRpc(request.multisigWitness)
|
|
207
215
|
if (typeof request.validBefore !== 'undefined')
|
|
208
216
|
request_rpc.validBefore = Hex.fromNumber(request.validBefore)
|
|
209
217
|
if (typeof request.validAfter !== 'undefined')
|
|
@@ -222,6 +230,7 @@ export function toRpc(request: TransactionRequest): Rpc {
|
|
|
222
230
|
typeof request.feePayer !== 'undefined' ||
|
|
223
231
|
typeof request.feeToken !== 'undefined' ||
|
|
224
232
|
typeof request.keyAuthorization !== 'undefined' ||
|
|
233
|
+
typeof request.multisigWitness !== 'undefined' ||
|
|
225
234
|
typeof request.nonceKey !== 'undefined' ||
|
|
226
235
|
typeof request.validBefore !== 'undefined' ||
|
|
227
236
|
typeof request.validAfter !== 'undefined' ||
|
|
@@ -240,6 +249,7 @@ export function toRpc(request: TransactionRequest): Rpc {
|
|
|
240
249
|
export declare namespace toRpc {
|
|
241
250
|
export type ErrorType =
|
|
242
251
|
| AuthorizationTempo.toRpcList.ErrorType
|
|
252
|
+
| MultisigWitness.toRpc.ErrorType
|
|
243
253
|
| Hex.fromNumber.ErrorType
|
|
244
254
|
| Errors.GlobalErrorType
|
|
245
255
|
}
|
package/tempo/index.ts
CHANGED
|
@@ -159,6 +159,15 @@ export * as MultisigConfig from './MultisigConfig.js'
|
|
|
159
159
|
* @category Reference
|
|
160
160
|
*/
|
|
161
161
|
export * as MultisigOperation from './MultisigOperation.js'
|
|
162
|
+
/**
|
|
163
|
+
* Native multisig RPC simulation witness utilities.
|
|
164
|
+
*
|
|
165
|
+
* Converts complete root and nested owner witnesses between their domain and
|
|
166
|
+
* Tempo JSON-RPC representations.
|
|
167
|
+
*
|
|
168
|
+
* @category Reference
|
|
169
|
+
*/
|
|
170
|
+
export * as MultisigWitness from './MultisigWitness.js'
|
|
162
171
|
/**
|
|
163
172
|
* Utilities for constructing period durations (in seconds) for recurring spending limits.
|
|
164
173
|
*
|
package/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** @internal */
|
|
2
|
-
export const version = '0.14.
|
|
2
|
+
export const version = '0.14.41'
|