ox 1.0.2 → 1.0.4
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/dist/tempo/EarnShares.d.ts +179 -0
- package/dist/tempo/EarnShares.d.ts.map +1 -0
- package/dist/tempo/EarnShares.js +160 -0
- package/dist/tempo/EarnShares.js.map +1 -0
- package/dist/tempo/KeyAuthorization.d.ts +22 -16
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/KeyAuthorization.js +31 -7
- package/dist/tempo/KeyAuthorization.js.map +1 -1
- package/dist/tempo/MultisigConfig.d.ts +8 -4
- package/dist/tempo/MultisigConfig.d.ts.map +1 -1
- package/dist/tempo/MultisigConfig.js +16 -4
- package/dist/tempo/MultisigConfig.js.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +31 -13
- package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/tempo/SignatureEnvelope.js +172 -55
- package/dist/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/tempo/index.d.ts +22 -0
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +22 -0
- package/dist/tempo/index.js.map +1 -1
- package/dist/zod/tempo/AuthorizationTempo.d.ts +70 -60
- package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.d.ts +0 -306
- package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.js +2 -2
- package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
- package/dist/zod/tempo/MultisigConfig.d.ts.map +1 -1
- package/dist/zod/tempo/MultisigConfig.js +5 -2
- package/dist/zod/tempo/MultisigConfig.js.map +1 -1
- package/dist/zod/tempo/RpcSchemaTempo.d.ts +28 -132
- package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.d.ts +79 -18
- package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.js +39 -11
- package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/zod/tempo/Transaction.d.ts +84 -396
- package/dist/zod/tempo/Transaction.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.d.ts +42 -234
- package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts +0 -108
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/tempo/EarnShares.test.ts +120 -0
- package/src/tempo/EarnShares.ts +235 -0
- package/src/tempo/KeyAuthorization.test-d.ts +62 -0
- package/src/tempo/KeyAuthorization.test.ts +53 -0
- package/src/tempo/KeyAuthorization.ts +69 -27
- package/src/tempo/MultisigConfig.test.ts +34 -2
- package/src/tempo/MultisigConfig.ts +18 -4
- package/src/tempo/SignatureEnvelope.test-d.ts +97 -0
- package/src/tempo/SignatureEnvelope.test.ts +247 -36
- package/src/tempo/SignatureEnvelope.ts +271 -85
- package/src/tempo/e2e.test.ts +0 -416
- package/src/tempo/index.ts +22 -0
- package/src/tempo/multisig.e2e.test.ts +582 -0
- package/src/version.ts +1 -1
- package/src/zod/tempo/KeyAuthorization.ts +2 -2
- package/src/zod/tempo/MultisigConfig.ts +13 -5
- package/src/zod/tempo/SignatureEnvelope.ts +81 -18
- package/src/zod/tempo/_test/KeyAuthorization.test.ts +25 -0
- package/src/zod/tempo/_test/MultisigConfig.test.ts +44 -0
- package/src/zod/tempo/_test/SignatureEnvelope.test-d.ts +9 -0
- package/src/zod/tempo/_test/SignatureEnvelope.test.ts +142 -6
|
@@ -4,7 +4,7 @@ import type * as Errors from '../core/Errors.js'
|
|
|
4
4
|
import * as Hash from '../core/Hash.js'
|
|
5
5
|
import * as Hex from '../core/Hex.js'
|
|
6
6
|
import * as Quantity from '../core/internal/quantity.js'
|
|
7
|
-
import type { Compute, OneOf } from '../core/internal/types.js'
|
|
7
|
+
import type { Compute, OneOf, UnionPartialBy } from '../core/internal/types.js'
|
|
8
8
|
import * as Rlp from '../core/Rlp.js'
|
|
9
9
|
import * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
10
10
|
|
|
@@ -78,9 +78,9 @@ export type KeyAuthorization<
|
|
|
78
78
|
| {}
|
|
79
79
|
> &
|
|
80
80
|
(signed extends true
|
|
81
|
-
? { signature: SignatureEnvelope.
|
|
81
|
+
? { signature: SignatureEnvelope.Primitive<numberType> }
|
|
82
82
|
: {
|
|
83
|
-
signature?: SignatureEnvelope.
|
|
83
|
+
signature?: SignatureEnvelope.Primitive<numberType> | undefined
|
|
84
84
|
})
|
|
85
85
|
|
|
86
86
|
/** Input type for a Key Authorization. */
|
|
@@ -104,8 +104,8 @@ export type Rpc = {
|
|
|
104
104
|
keyType: SignatureEnvelope.Type
|
|
105
105
|
/** Token spending limits. */
|
|
106
106
|
limits?: readonly RpcTokenLimit[] | null | undefined
|
|
107
|
-
/**
|
|
108
|
-
signature: SignatureEnvelope.
|
|
107
|
+
/** Primitive signature authorizing this key. */
|
|
108
|
+
signature: SignatureEnvelope.PrimitiveRpc
|
|
109
109
|
/** Optional 32-byte witness (hex). */
|
|
110
110
|
witness?: Hex.Hex | null | undefined
|
|
111
111
|
}
|
|
@@ -136,6 +136,11 @@ export type Signed<bigintType = bigint, numberType = number> = KeyAuthorization<
|
|
|
136
136
|
numberType
|
|
137
137
|
>
|
|
138
138
|
|
|
139
|
+
type PrimitiveSignatureValue =
|
|
140
|
+
| UnionPartialBy<SignatureEnvelope.Primitive, 'prehash' | 'type'>
|
|
141
|
+
| SignatureEnvelope.Secp256k1Flat
|
|
142
|
+
| SignatureEnvelope.Serialized
|
|
143
|
+
|
|
139
144
|
type BaseTuple = readonly [
|
|
140
145
|
chainId: Hex.Hex,
|
|
141
146
|
keyType: Hex.Hex,
|
|
@@ -415,7 +420,7 @@ export type TokenLimit<bigintType = bigint, numberType = number> = {
|
|
|
415
420
|
*/
|
|
416
421
|
export function from<
|
|
417
422
|
const authorization extends Input | Rpc,
|
|
418
|
-
const signature extends
|
|
423
|
+
const signature extends PrimitiveSignatureValue | undefined = undefined,
|
|
419
424
|
>(
|
|
420
425
|
authorization: authorization | KeyAuthorization,
|
|
421
426
|
options: from.Options<signature> = {},
|
|
@@ -430,6 +435,7 @@ export function from<
|
|
|
430
435
|
}[]
|
|
431
436
|
}
|
|
432
437
|
if (auth.witness !== undefined) assertWitness(auth.witness)
|
|
438
|
+
if (auth.signature) assertSignature(auth.signature)
|
|
433
439
|
const resolved = {
|
|
434
440
|
...auth,
|
|
435
441
|
...(auth.scopes
|
|
@@ -441,39 +447,49 @@ export function from<
|
|
|
441
447
|
}
|
|
442
448
|
: {}),
|
|
443
449
|
}
|
|
444
|
-
if (options.signature)
|
|
450
|
+
if (options.signature) {
|
|
451
|
+
const signature = SignatureEnvelope.from(
|
|
452
|
+
options.signature,
|
|
453
|
+
) as SignatureEnvelope.SignatureEnvelope
|
|
454
|
+
assertSignature(signature)
|
|
445
455
|
return {
|
|
446
456
|
...resolved,
|
|
447
|
-
signature
|
|
457
|
+
signature,
|
|
448
458
|
} as never
|
|
459
|
+
}
|
|
449
460
|
return resolved as never
|
|
450
461
|
}
|
|
451
462
|
|
|
452
463
|
export declare namespace from {
|
|
453
464
|
type Options<
|
|
454
|
-
signature extends
|
|
455
|
-
|
|
|
465
|
+
signature extends PrimitiveSignatureValue | undefined =
|
|
466
|
+
| PrimitiveSignatureValue
|
|
456
467
|
| undefined,
|
|
457
468
|
> = {
|
|
458
|
-
/** The
|
|
459
|
-
signature?: signature | SignatureEnvelope.
|
|
469
|
+
/** The primitive signature to attach to the Key Authorization. */
|
|
470
|
+
signature?: signature | SignatureEnvelope.Primitive | undefined
|
|
460
471
|
}
|
|
461
472
|
|
|
462
473
|
type ReturnType<
|
|
463
474
|
authorization extends KeyAuthorization | Input | Rpc = KeyAuthorization,
|
|
464
|
-
signature extends
|
|
465
|
-
|
|
|
475
|
+
signature extends PrimitiveSignatureValue | undefined =
|
|
476
|
+
| PrimitiveSignatureValue
|
|
466
477
|
| undefined,
|
|
467
478
|
> = Compute<
|
|
468
479
|
authorization extends Rpc
|
|
469
480
|
? Signed
|
|
470
481
|
: authorization &
|
|
471
|
-
(signature extends
|
|
472
|
-
? {
|
|
482
|
+
(signature extends PrimitiveSignatureValue
|
|
483
|
+
? {
|
|
484
|
+
signature: Extract<
|
|
485
|
+
SignatureEnvelope.from.ReturnValue<signature>,
|
|
486
|
+
SignatureEnvelope.Primitive
|
|
487
|
+
>
|
|
488
|
+
}
|
|
473
489
|
: {})
|
|
474
490
|
>
|
|
475
491
|
|
|
476
|
-
type ErrorType = Errors.GlobalErrorType
|
|
492
|
+
type ErrorType = InvalidSignatureTypeError | Errors.GlobalErrorType
|
|
477
493
|
}
|
|
478
494
|
|
|
479
495
|
/**
|
|
@@ -513,6 +529,7 @@ export function fromRpc(authorization: Rpc): Signed {
|
|
|
513
529
|
const isAdmin = authorization.isAdmin ?? undefined
|
|
514
530
|
const account = authorization.account ?? undefined
|
|
515
531
|
const signature = SignatureEnvelope.fromRpc(authorization.signature)
|
|
532
|
+
assertSignature(signature)
|
|
516
533
|
if (witness !== undefined) assertWitness(witness)
|
|
517
534
|
|
|
518
535
|
// Unflatten nested allowedCalls into flat scopes
|
|
@@ -558,7 +575,7 @@ export function fromRpc(authorization: Rpc): Signed {
|
|
|
558
575
|
}
|
|
559
576
|
|
|
560
577
|
export declare namespace fromRpc {
|
|
561
|
-
type ErrorType = Errors.GlobalErrorType
|
|
578
|
+
type ErrorType = InvalidSignatureTypeError | Errors.GlobalErrorType
|
|
562
579
|
}
|
|
563
580
|
|
|
564
581
|
/**
|
|
@@ -700,8 +717,11 @@ export function fromTuple<const tuple extends Tuple>(
|
|
|
700
717
|
...(witness !== undefined ? { witness } : {}),
|
|
701
718
|
...adminPair,
|
|
702
719
|
}
|
|
703
|
-
if (signatureSerialized)
|
|
704
|
-
|
|
720
|
+
if (signatureSerialized) {
|
|
721
|
+
const signature = SignatureEnvelope.deserialize(signatureSerialized)
|
|
722
|
+
assertSignature(signature)
|
|
723
|
+
args.signature = signature
|
|
724
|
+
}
|
|
705
725
|
return from(args) as never
|
|
706
726
|
}
|
|
707
727
|
|
|
@@ -710,7 +730,7 @@ export declare namespace fromTuple {
|
|
|
710
730
|
KeyAuthorization<authorization extends Tuple<true> ? true : false>
|
|
711
731
|
>
|
|
712
732
|
|
|
713
|
-
type ErrorType = Errors.GlobalErrorType
|
|
733
|
+
type ErrorType = InvalidSignatureTypeError | Errors.GlobalErrorType
|
|
714
734
|
}
|
|
715
735
|
|
|
716
736
|
/**
|
|
@@ -928,6 +948,7 @@ export function toRpc(authorization: toRpc.Input): Rpc {
|
|
|
928
948
|
isAdmin,
|
|
929
949
|
account,
|
|
930
950
|
} = authorization
|
|
951
|
+
assertSignature(signature)
|
|
931
952
|
if (witness !== undefined) assertWitness(witness)
|
|
932
953
|
|
|
933
954
|
// Group flat scopes by address into nested allowedCalls wire format
|
|
@@ -966,7 +987,9 @@ export function toRpc(authorization: toRpc.Input): Rpc {
|
|
|
966
987
|
limit: Quantity.fromNumberish(limit),
|
|
967
988
|
...(period ? { period: Quantity.fromNumberish(period) } : {}),
|
|
968
989
|
})),
|
|
969
|
-
signature: SignatureEnvelope.toRpc(
|
|
990
|
+
signature: SignatureEnvelope.toRpc(
|
|
991
|
+
signature,
|
|
992
|
+
) as SignatureEnvelope.PrimitiveRpc,
|
|
970
993
|
...(allowedCalls ? { allowedCalls } : {}),
|
|
971
994
|
...(witness !== undefined ? { witness } : {}),
|
|
972
995
|
...(isAdmin ? { isAdmin: true } : {}),
|
|
@@ -978,7 +1001,7 @@ export declare namespace toRpc {
|
|
|
978
1001
|
/** Numberish input accepted by {@link ox#KeyAuthorization.(toRpc:function)}. */
|
|
979
1002
|
type Input = Signed<Hex.Hex | bigint | number, Hex.Hex | number>
|
|
980
1003
|
|
|
981
|
-
type ErrorType = Errors.GlobalErrorType
|
|
1004
|
+
type ErrorType = InvalidSignatureTypeError | Errors.GlobalErrorType
|
|
982
1005
|
}
|
|
983
1006
|
|
|
984
1007
|
/**
|
|
@@ -1028,9 +1051,11 @@ export function toTuple<const authorization extends KeyAuthorization>(
|
|
|
1028
1051
|
account,
|
|
1029
1052
|
} = authorization
|
|
1030
1053
|
if (witness !== undefined) assertWitness(witness)
|
|
1031
|
-
const signature =
|
|
1032
|
-
|
|
1033
|
-
|
|
1054
|
+
const signature = (() => {
|
|
1055
|
+
if (!authorization.signature) return undefined
|
|
1056
|
+
assertSignature(authorization.signature)
|
|
1057
|
+
return SignatureEnvelope.serialize(authorization.signature)
|
|
1058
|
+
})()
|
|
1034
1059
|
const type = (() => {
|
|
1035
1060
|
switch (authorization.type) {
|
|
1036
1061
|
case 'secp256k1':
|
|
@@ -1126,7 +1151,7 @@ export declare namespace toTuple {
|
|
|
1126
1151
|
type ReturnType<authorization extends KeyAuthorization = KeyAuthorization> =
|
|
1127
1152
|
Compute<Tuple<authorization extends KeyAuthorization<true> ? true : false>>
|
|
1128
1153
|
|
|
1129
|
-
type ErrorType = Errors.GlobalErrorType
|
|
1154
|
+
type ErrorType = InvalidSignatureTypeError | Errors.GlobalErrorType
|
|
1130
1155
|
}
|
|
1131
1156
|
|
|
1132
1157
|
function bigintToHex(value: bigint): Hex.Hex {
|
|
@@ -1164,6 +1189,13 @@ function assertWitness(witness: Hex.Hex): void {
|
|
|
1164
1189
|
if (Hex.size(witness) !== 32) throw new InvalidWitnessSizeError(witness)
|
|
1165
1190
|
}
|
|
1166
1191
|
|
|
1192
|
+
function assertSignature<numberType>(
|
|
1193
|
+
signature: SignatureEnvelope.SignatureEnvelope<numberType>,
|
|
1194
|
+
): asserts signature is SignatureEnvelope.Primitive<numberType> {
|
|
1195
|
+
if (signature.type === 'keychain' || signature.type === 'multisig')
|
|
1196
|
+
throw new InvalidSignatureTypeError(signature.type)
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1167
1199
|
function isAbsent(value: unknown): boolean {
|
|
1168
1200
|
return value === undefined || value === '0x'
|
|
1169
1201
|
}
|
|
@@ -1187,3 +1219,13 @@ export class InvalidAdminMarkerError extends Error {
|
|
|
1187
1219
|
)
|
|
1188
1220
|
}
|
|
1189
1221
|
}
|
|
1222
|
+
|
|
1223
|
+
/** Thrown when a key authorization contains a non-primitive signature. */
|
|
1224
|
+
export class InvalidSignatureTypeError extends Error {
|
|
1225
|
+
override readonly name = 'KeyAuthorization.InvalidSignatureTypeError'
|
|
1226
|
+
constructor(type: SignatureEnvelope.SignatureEnvelope['type']) {
|
|
1227
|
+
super(
|
|
1228
|
+
`Signature type \`${type}\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, or \`webAuthn\`.`,
|
|
1229
|
+
)
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
@@ -154,7 +154,12 @@ describe('assert / validate', () => {
|
|
|
154
154
|
owner: `0x${(i + 1).toString(16).padStart(40, '0')}` as `0x${string}`,
|
|
155
155
|
weight: 1,
|
|
156
156
|
}))
|
|
157
|
-
expect(
|
|
157
|
+
expect(
|
|
158
|
+
MultisigConfig.validate({
|
|
159
|
+
threshold: MultisigConfig.maxThreshold,
|
|
160
|
+
owners,
|
|
161
|
+
}),
|
|
162
|
+
).toBe(true)
|
|
158
163
|
})
|
|
159
164
|
|
|
160
165
|
test('too many owners', () => {
|
|
@@ -174,6 +179,24 @@ describe('assert / validate', () => {
|
|
|
174
179
|
).toBe(false)
|
|
175
180
|
})
|
|
176
181
|
|
|
182
|
+
test('threshold exceeds protocol maximum', () => {
|
|
183
|
+
expect(
|
|
184
|
+
MultisigConfig.validate({
|
|
185
|
+
threshold: MultisigConfig.maxThreshold + 1,
|
|
186
|
+
owners: [{ owner: owner1, weight: MultisigConfig.maxThreshold + 1 }],
|
|
187
|
+
}),
|
|
188
|
+
).toBe(false)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test('fractional threshold', () => {
|
|
192
|
+
expect(
|
|
193
|
+
MultisigConfig.validate({
|
|
194
|
+
threshold: 1.5,
|
|
195
|
+
owners: [{ owner: owner1, weight: 2 }],
|
|
196
|
+
}),
|
|
197
|
+
).toBe(false)
|
|
198
|
+
})
|
|
199
|
+
|
|
177
200
|
test('threshold exceeds total weight', () => {
|
|
178
201
|
expect(
|
|
179
202
|
MultisigConfig.validate({
|
|
@@ -186,7 +209,7 @@ describe('assert / validate', () => {
|
|
|
186
209
|
test('total weight exceeds u8 max', () => {
|
|
187
210
|
expect(
|
|
188
211
|
MultisigConfig.validate({
|
|
189
|
-
threshold:
|
|
212
|
+
threshold: MultisigConfig.maxThreshold,
|
|
190
213
|
owners: [
|
|
191
214
|
{ owner: owner1, weight: 128 },
|
|
192
215
|
{ owner: owner2, weight: 128 },
|
|
@@ -204,6 +227,15 @@ describe('assert / validate', () => {
|
|
|
204
227
|
).toBe(false)
|
|
205
228
|
})
|
|
206
229
|
|
|
230
|
+
test('fractional owner weight', () => {
|
|
231
|
+
expect(
|
|
232
|
+
MultisigConfig.validate({
|
|
233
|
+
threshold: 1,
|
|
234
|
+
owners: [{ owner: owner1, weight: 1.5 }],
|
|
235
|
+
}),
|
|
236
|
+
).toBe(false)
|
|
237
|
+
})
|
|
238
|
+
|
|
207
239
|
test('zero owner address', () => {
|
|
208
240
|
expect(
|
|
209
241
|
MultisigConfig.validate({
|
|
@@ -8,13 +8,19 @@ import type { Compute, OneOf } from '../core/internal/types.js'
|
|
|
8
8
|
/** Maximum number of owners allowed in a native multisig config. */
|
|
9
9
|
export const maxOwners = 255
|
|
10
10
|
|
|
11
|
+
/** Maximum threshold accepted by a native multisig config. */
|
|
12
|
+
export const maxThreshold = 8
|
|
13
|
+
|
|
14
|
+
/** Maximum number of owner approvals in a native multisig signature. */
|
|
15
|
+
export const maxSignatures = maxThreshold
|
|
16
|
+
|
|
11
17
|
/**
|
|
12
18
|
* Maximum number of native multisig signatures in one nested authorization
|
|
13
19
|
* path, including the top-level transaction signature.
|
|
14
20
|
*/
|
|
15
|
-
export const maxNestingDepth =
|
|
21
|
+
export const maxNestingDepth = 2
|
|
16
22
|
|
|
17
|
-
/** Maximum encoded byte length for one
|
|
23
|
+
/** Maximum encoded byte length for one owner approval. */
|
|
18
24
|
export const maxOwnerSignatureBytes = 2049
|
|
19
25
|
|
|
20
26
|
/** Tempo signature type byte for native multisig signatures. */
|
|
@@ -65,8 +71,8 @@ export type Tuple = readonly [
|
|
|
65
71
|
*
|
|
66
72
|
* Mirrors the Tempo `InitMultisig::validate` rules: owners non-empty and
|
|
67
73
|
* `<= maxOwners`, strictly ascending unique nonzero owner addresses, nonzero
|
|
68
|
-
* owner weights, `threshold
|
|
69
|
-
* `threshold <= total weight`.
|
|
74
|
+
* integer owner weights, integer `threshold` between `1` and `maxThreshold`,
|
|
75
|
+
* total weight `<= 255` (u8 max), and `threshold <= total weight`.
|
|
70
76
|
*
|
|
71
77
|
* @example
|
|
72
78
|
* ```ts twoslash
|
|
@@ -94,14 +100,22 @@ export function assert<numberType = number>(config: Config<numberType>): void {
|
|
|
94
100
|
throw new InvalidConfigError({ reason: 'owners cannot be empty' })
|
|
95
101
|
if (owners.length > maxOwners)
|
|
96
102
|
throw new InvalidConfigError({ reason: 'too many owners' })
|
|
103
|
+
if (!Number.isInteger(Number(threshold)))
|
|
104
|
+
throw new InvalidConfigError({ reason: 'threshold must be an integer' })
|
|
97
105
|
if (Number(threshold) < 1)
|
|
98
106
|
throw new InvalidConfigError({ reason: 'threshold cannot be zero' })
|
|
107
|
+
if (Number(threshold) > maxThreshold)
|
|
108
|
+
throw new InvalidConfigError({ reason: 'threshold exceeds max threshold' })
|
|
99
109
|
|
|
100
110
|
let totalWeight = 0
|
|
101
111
|
let previous: bigint | undefined
|
|
102
112
|
for (const owner of owners) {
|
|
103
113
|
if (!Address.validate(owner.owner) || Hex.toBigInt(owner.owner) === 0n)
|
|
104
114
|
throw new InvalidConfigError({ reason: 'owner cannot be zero' })
|
|
115
|
+
if (!Number.isInteger(Number(owner.weight)))
|
|
116
|
+
throw new InvalidConfigError({
|
|
117
|
+
reason: 'owner weight must be an integer',
|
|
118
|
+
})
|
|
105
119
|
if (Number(owner.weight) < 1)
|
|
106
120
|
throw new InvalidConfigError({ reason: 'owner weight cannot be zero' })
|
|
107
121
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { expectTypeOf, test } from 'vp/test'
|
|
2
|
+
import * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
3
|
+
|
|
4
|
+
const signature = {
|
|
5
|
+
r: '0x01',
|
|
6
|
+
s: '0x02',
|
|
7
|
+
type: 'secp256k1',
|
|
8
|
+
yParity: '0x0',
|
|
9
|
+
} as const satisfies SignatureEnvelope.SignatureEnvelopeRpc
|
|
10
|
+
|
|
11
|
+
const signatureDomain = {
|
|
12
|
+
signature: {
|
|
13
|
+
r: '0x01',
|
|
14
|
+
s: '0x02',
|
|
15
|
+
yParity: 0,
|
|
16
|
+
},
|
|
17
|
+
type: 'secp256k1',
|
|
18
|
+
} as const satisfies SignatureEnvelope.Secp256k1
|
|
19
|
+
|
|
20
|
+
test('toRpc preserves the signature type', () => {
|
|
21
|
+
expectTypeOf(
|
|
22
|
+
SignatureEnvelope.toRpc(signatureDomain),
|
|
23
|
+
).toEqualTypeOf<SignatureEnvelope.Secp256k1Rpc>()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('MultisigRpc uses static initialized and bootstrap shapes', () => {
|
|
27
|
+
const initialized = {
|
|
28
|
+
account: '0x1111111111111111111111111111111111111111',
|
|
29
|
+
signatures: [signature],
|
|
30
|
+
} as const satisfies SignatureEnvelope.MultisigRpc
|
|
31
|
+
const bootstrap = {
|
|
32
|
+
init: {
|
|
33
|
+
owners: [
|
|
34
|
+
{
|
|
35
|
+
owner: '0x1111111111111111111111111111111111111111',
|
|
36
|
+
weight: 1,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
threshold: 1,
|
|
40
|
+
},
|
|
41
|
+
signatures: [signature],
|
|
42
|
+
} as const satisfies SignatureEnvelope.MultisigRpc
|
|
43
|
+
const bootstrapWithAccountUndefined: SignatureEnvelope.MultisigRpc = {
|
|
44
|
+
...bootstrap,
|
|
45
|
+
account: undefined,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
expectTypeOf(initialized.signatures).toMatchTypeOf<
|
|
49
|
+
readonly SignatureEnvelope.SignatureEnvelopeRpc[]
|
|
50
|
+
>()
|
|
51
|
+
expectTypeOf(bootstrap.signatures).toMatchTypeOf<
|
|
52
|
+
readonly SignatureEnvelope.SignatureEnvelopeRpc[]
|
|
53
|
+
>()
|
|
54
|
+
expectTypeOf(
|
|
55
|
+
bootstrapWithAccountUndefined,
|
|
56
|
+
).toMatchTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
57
|
+
expectTypeOf<
|
|
58
|
+
SignatureEnvelope.GetType<typeof bootstrap>
|
|
59
|
+
>().toEqualTypeOf<'multisig'>()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('MultisigRpc rejects legacy shapes', () => {
|
|
63
|
+
const combined = {
|
|
64
|
+
account: '0x1111111111111111111111111111111111111111',
|
|
65
|
+
init: {
|
|
66
|
+
owners: [
|
|
67
|
+
{
|
|
68
|
+
owner: '0x1111111111111111111111111111111111111111',
|
|
69
|
+
weight: 1,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
threshold: 1,
|
|
73
|
+
},
|
|
74
|
+
signatures: [signature],
|
|
75
|
+
} as const
|
|
76
|
+
// @ts-expect-error Bootstrap RPC signatures omit `account`.
|
|
77
|
+
const combinedRpc: SignatureEnvelope.MultisigRpc = combined
|
|
78
|
+
|
|
79
|
+
const serialized = {
|
|
80
|
+
account: '0x1111111111111111111111111111111111111111',
|
|
81
|
+
signatures: ['0x1234'],
|
|
82
|
+
} as const
|
|
83
|
+
// @ts-expect-error Owner approvals use structured RPC envelopes.
|
|
84
|
+
const serializedRpc: SignatureEnvelope.MultisigRpc = serialized
|
|
85
|
+
|
|
86
|
+
const tagged = {
|
|
87
|
+
account: '0x1111111111111111111111111111111111111111',
|
|
88
|
+
signatures: [signature],
|
|
89
|
+
type: 'multisig',
|
|
90
|
+
} as const
|
|
91
|
+
// @ts-expect-error Multisig RPC signatures are untagged.
|
|
92
|
+
const taggedRpc: SignatureEnvelope.MultisigRpc = tagged
|
|
93
|
+
|
|
94
|
+
expectTypeOf(combinedRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
95
|
+
expectTypeOf(serializedRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
96
|
+
expectTypeOf(taggedRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
|
|
97
|
+
})
|