ox 0.14.32 → 0.14.34
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 +24 -0
- package/_cjs/tempo/KeyAuthorization.js +6 -6
- package/_cjs/tempo/KeyAuthorization.js.map +1 -1
- package/_cjs/tempo/MultisigConfig.js +4 -4
- package/_cjs/tempo/MultisigConfig.js.map +1 -1
- package/_cjs/tempo/SignatureEnvelope.js +23 -15
- package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
- package/_cjs/tempo/ZoneId.js +38 -6
- package/_cjs/tempo/ZoneId.js.map +1 -1
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/tempo/KeyAuthorization.js +7 -13
- package/_esm/tempo/KeyAuthorization.js.map +1 -1
- package/_esm/tempo/MultisigConfig.js +17 -16
- package/_esm/tempo/MultisigConfig.js.map +1 -1
- package/_esm/tempo/SignatureEnvelope.js +42 -28
- package/_esm/tempo/SignatureEnvelope.js.map +1 -1
- package/_esm/tempo/ZoneId.js +46 -16
- package/_esm/tempo/ZoneId.js.map +1 -1
- package/_esm/tempo/index.js +7 -8
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/tempo/KeyAuthorization.d.ts +16 -12
- package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
- package/_types/tempo/MultisigConfig.d.ts +20 -17
- package/_types/tempo/MultisigConfig.d.ts.map +1 -1
- package/_types/tempo/SignatureEnvelope.d.ts +26 -18
- package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/_types/tempo/ZoneId.d.ts +35 -17
- package/_types/tempo/ZoneId.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +7 -8
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/package.json +6 -1
- package/tempo/KeyAuthorization.test-d.ts +41 -6
- package/tempo/KeyAuthorization.test.ts +106 -60
- package/tempo/KeyAuthorization.ts +36 -38
- package/tempo/MultisigConfig.test.ts +28 -8
- package/tempo/MultisigConfig.ts +28 -19
- package/tempo/SignatureEnvelope.test.ts +64 -19
- package/tempo/SignatureEnvelope.ts +52 -36
- package/tempo/ZoneId.test-d/package.json +6 -0
- package/tempo/ZoneId.test-d.ts +16 -0
- package/tempo/ZoneId.test.ts +48 -13
- package/tempo/ZoneId.ts +55 -19
- package/tempo/index.ts +7 -8
- package/tempo/multisig.e2e.test.ts +402 -145
- package/version.ts +1 -1
|
@@ -23,6 +23,12 @@ const multisig = {
|
|
|
23
23
|
type: 'multisig',
|
|
24
24
|
} as const satisfies SignatureEnvelope.Multisig
|
|
25
25
|
|
|
26
|
+
const keychain = {
|
|
27
|
+
inner: signature,
|
|
28
|
+
type: 'keychain',
|
|
29
|
+
userAddress: authorization.address,
|
|
30
|
+
} as const satisfies SignatureEnvelope.Keychain
|
|
31
|
+
|
|
26
32
|
test('accepts primitive signatures', () => {
|
|
27
33
|
const signed = KeyAuthorization.from(authorization, { signature })
|
|
28
34
|
|
|
@@ -31,11 +37,12 @@ test('accepts primitive signatures', () => {
|
|
|
31
37
|
>()
|
|
32
38
|
})
|
|
33
39
|
|
|
34
|
-
test('
|
|
35
|
-
KeyAuthorization.from(authorization, {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
test('accepts multisig signatures', () => {
|
|
41
|
+
const signed = KeyAuthorization.from(authorization, { signature: multisig })
|
|
42
|
+
|
|
43
|
+
expectTypeOf(signed.signature).toMatchTypeOf<
|
|
44
|
+
KeyAuthorization.Signed['signature']
|
|
45
|
+
>()
|
|
39
46
|
|
|
40
47
|
const multisigRpc = {
|
|
41
48
|
account: multisig.account,
|
|
@@ -54,9 +61,37 @@ test('rejects multisig signatures', () => {
|
|
|
54
61
|
expiry: null,
|
|
55
62
|
keyId: authorization.address,
|
|
56
63
|
keyType: authorization.type,
|
|
57
|
-
// @ts-expect-error Key authorizations accept only primitive RPC signatures.
|
|
58
64
|
signature: multisigRpc,
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
expectTypeOf(rpc).toEqualTypeOf<KeyAuthorization.Rpc>()
|
|
62
68
|
})
|
|
69
|
+
|
|
70
|
+
test('rejects keychain signatures', () => {
|
|
71
|
+
KeyAuthorization.from(authorization, {
|
|
72
|
+
// @ts-expect-error Key authorizations do not accept keychain signatures.
|
|
73
|
+
signature: keychain,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const keychainRpc = {
|
|
77
|
+
signature: {
|
|
78
|
+
r: '0x01',
|
|
79
|
+
s: '0x02',
|
|
80
|
+
type: 'secp256k1',
|
|
81
|
+
yParity: '0x0',
|
|
82
|
+
},
|
|
83
|
+
type: 'keychain',
|
|
84
|
+
userAddress: authorization.address,
|
|
85
|
+
} as const satisfies SignatureEnvelope.KeychainRpc
|
|
86
|
+
|
|
87
|
+
const rpc: KeyAuthorization.Rpc = {
|
|
88
|
+
chainId: '0x1',
|
|
89
|
+
expiry: null,
|
|
90
|
+
keyId: authorization.address,
|
|
91
|
+
keyType: authorization.type,
|
|
92
|
+
// @ts-expect-error Key authorizations do not accept keychain RPC signatures.
|
|
93
|
+
signature: keychainRpc,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
expectTypeOf(rpc).toEqualTypeOf<KeyAuthorization.Rpc>()
|
|
97
|
+
})
|
|
@@ -53,11 +53,17 @@ const signature_webauthn = SignatureEnvelope.from({
|
|
|
53
53
|
},
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
const signature_multisig =
|
|
56
|
+
const signature_multisig = {
|
|
57
57
|
account: address,
|
|
58
58
|
signatures: [SignatureEnvelope.from(signature_secp256k1)],
|
|
59
59
|
type: 'multisig',
|
|
60
|
-
}
|
|
60
|
+
} as const satisfies SignatureEnvelope.Multisig
|
|
61
|
+
|
|
62
|
+
const signature_keychain = {
|
|
63
|
+
inner: SignatureEnvelope.from(signature_secp256k1),
|
|
64
|
+
type: 'keychain',
|
|
65
|
+
userAddress: address,
|
|
66
|
+
} as const satisfies SignatureEnvelope.Keychain
|
|
61
67
|
|
|
62
68
|
describe('from', () => {
|
|
63
69
|
test('default', () => {
|
|
@@ -448,7 +454,34 @@ describe('from', () => {
|
|
|
448
454
|
`)
|
|
449
455
|
})
|
|
450
456
|
|
|
451
|
-
test('
|
|
457
|
+
test('with signature (multisig)', () => {
|
|
458
|
+
const authorization = KeyAuthorization.from({
|
|
459
|
+
address,
|
|
460
|
+
chainId: 1n,
|
|
461
|
+
type: 'secp256k1',
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
const signed = KeyAuthorization.from(authorization, {
|
|
465
|
+
signature: signature_multisig,
|
|
466
|
+
})
|
|
467
|
+
expect(signed.signature).toEqual(signature_multisig)
|
|
468
|
+
expect(
|
|
469
|
+
KeyAuthorization.from(authorization, {
|
|
470
|
+
signature: SignatureEnvelope.serialize(signature_multisig),
|
|
471
|
+
}).signature,
|
|
472
|
+
).toEqual(signature_multisig)
|
|
473
|
+
expect(
|
|
474
|
+
KeyAuthorization.from({
|
|
475
|
+
...authorization,
|
|
476
|
+
signature: signature_multisig,
|
|
477
|
+
}).signature,
|
|
478
|
+
).toEqual(signature_multisig)
|
|
479
|
+
expect(
|
|
480
|
+
KeyAuthorization.deserialize(KeyAuthorization.serialize(signed)),
|
|
481
|
+
).toEqual(signed)
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
test('rejects a keychain signature', () => {
|
|
452
485
|
const authorization = KeyAuthorization.from({
|
|
453
486
|
address,
|
|
454
487
|
chainId: 1n,
|
|
@@ -457,50 +490,55 @@ describe('from', () => {
|
|
|
457
490
|
|
|
458
491
|
expect(() =>
|
|
459
492
|
KeyAuthorization.from(authorization, {
|
|
460
|
-
signature:
|
|
493
|
+
signature: signature_keychain as never,
|
|
461
494
|
}),
|
|
462
495
|
).toThrowErrorMatchingInlineSnapshot(
|
|
463
|
-
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`
|
|
496
|
+
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`keychain\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, \`webAuthn\`, or \`multisig\`.]`,
|
|
464
497
|
)
|
|
465
498
|
|
|
466
499
|
expect(() =>
|
|
467
500
|
KeyAuthorization.from(authorization, {
|
|
468
|
-
signature: SignatureEnvelope.serialize(
|
|
501
|
+
signature: SignatureEnvelope.serialize(signature_keychain),
|
|
469
502
|
}),
|
|
470
503
|
).toThrowErrorMatchingInlineSnapshot(
|
|
471
|
-
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`
|
|
504
|
+
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`keychain\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, \`webAuthn\`, or \`multisig\`.]`,
|
|
472
505
|
)
|
|
473
506
|
|
|
474
507
|
expect(() =>
|
|
475
508
|
KeyAuthorization.from({
|
|
476
509
|
...authorization,
|
|
477
|
-
signature:
|
|
510
|
+
signature: signature_keychain,
|
|
478
511
|
} as never),
|
|
479
512
|
).toThrowErrorMatchingInlineSnapshot(
|
|
480
|
-
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`
|
|
513
|
+
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`keychain\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, \`webAuthn\`, or \`multisig\`.]`,
|
|
481
514
|
)
|
|
482
515
|
})
|
|
483
516
|
})
|
|
484
517
|
|
|
485
518
|
describe('fromRpc', () => {
|
|
486
|
-
test('
|
|
519
|
+
test('multisig', () => {
|
|
520
|
+
const authorization = KeyAuthorization.fromRpc({
|
|
521
|
+
chainId: '0x1',
|
|
522
|
+
expiry: null,
|
|
523
|
+
keyId: address,
|
|
524
|
+
keyType: 'secp256k1',
|
|
525
|
+
signature: SignatureEnvelope.toRpc(signature_multisig),
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
expect(authorization.signature).toEqual(signature_multisig)
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
test('rejects a keychain signature', () => {
|
|
487
532
|
expect(() =>
|
|
488
533
|
KeyAuthorization.fromRpc({
|
|
489
534
|
chainId: '0x1',
|
|
490
535
|
expiry: null,
|
|
491
536
|
keyId: address,
|
|
492
537
|
keyType: 'secp256k1',
|
|
493
|
-
signature:
|
|
494
|
-
account: address,
|
|
495
|
-
signatures: [
|
|
496
|
-
SignatureEnvelope.toRpc(
|
|
497
|
-
SignatureEnvelope.from(signature_secp256k1),
|
|
498
|
-
),
|
|
499
|
-
],
|
|
500
|
-
},
|
|
538
|
+
signature: SignatureEnvelope.toRpc(signature_keychain),
|
|
501
539
|
} as never),
|
|
502
540
|
).toThrowErrorMatchingInlineSnapshot(
|
|
503
|
-
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`
|
|
541
|
+
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`keychain\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, \`webAuthn\`, or \`multisig\`.]`,
|
|
504
542
|
)
|
|
505
543
|
})
|
|
506
544
|
|
|
@@ -721,15 +759,13 @@ describe('fromRpc', () => {
|
|
|
721
759
|
})
|
|
722
760
|
|
|
723
761
|
describe('fromTuple', () => {
|
|
724
|
-
test('
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
).
|
|
731
|
-
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`multisig\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, or \`webAuthn\`.]`,
|
|
732
|
-
)
|
|
762
|
+
test('multisig', () => {
|
|
763
|
+
const authorization = KeyAuthorization.fromTuple([
|
|
764
|
+
['0x1', '0x', address],
|
|
765
|
+
SignatureEnvelope.serialize(signature_multisig),
|
|
766
|
+
])
|
|
767
|
+
|
|
768
|
+
expect(authorization.signature).toEqual(signature_multisig)
|
|
733
769
|
})
|
|
734
770
|
|
|
735
771
|
test('default', () => {
|
|
@@ -1069,16 +1105,14 @@ describe('getSignPayload', () => {
|
|
|
1069
1105
|
})
|
|
1070
1106
|
|
|
1071
1107
|
describe('deserialize', () => {
|
|
1072
|
-
test('
|
|
1108
|
+
test('multisig', () => {
|
|
1073
1109
|
const serialized = Rlp.fromHex([
|
|
1074
1110
|
['0x1', '0x', address],
|
|
1075
1111
|
SignatureEnvelope.serialize(signature_multisig),
|
|
1076
1112
|
])
|
|
1077
1113
|
|
|
1078
|
-
expect(()
|
|
1079
|
-
|
|
1080
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
1081
|
-
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`multisig\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, or \`webAuthn\`.]`,
|
|
1114
|
+
expect(KeyAuthorization.deserialize(serialized).signature).toEqual(
|
|
1115
|
+
signature_multisig,
|
|
1082
1116
|
)
|
|
1083
1117
|
})
|
|
1084
1118
|
|
|
@@ -1252,16 +1286,16 @@ describe('serialize', () => {
|
|
|
1252
1286
|
})
|
|
1253
1287
|
|
|
1254
1288
|
describe('toRpc', () => {
|
|
1255
|
-
test('
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
).
|
|
1264
|
-
|
|
1289
|
+
test('multisig', () => {
|
|
1290
|
+
const authorization = KeyAuthorization.toRpc({
|
|
1291
|
+
address,
|
|
1292
|
+
chainId: 1n,
|
|
1293
|
+
signature: signature_multisig,
|
|
1294
|
+
type: 'secp256k1',
|
|
1295
|
+
})
|
|
1296
|
+
|
|
1297
|
+
expect(authorization.signature).toEqual(
|
|
1298
|
+
SignatureEnvelope.toRpc(signature_multisig),
|
|
1265
1299
|
)
|
|
1266
1300
|
})
|
|
1267
1301
|
|
|
@@ -1522,17 +1556,15 @@ describe('toRpc', () => {
|
|
|
1522
1556
|
})
|
|
1523
1557
|
|
|
1524
1558
|
describe('toTuple', () => {
|
|
1525
|
-
test('
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
).
|
|
1534
|
-
`[KeyAuthorization.InvalidSignatureTypeError: Signature type \`multisig\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, or \`webAuthn\`.]`,
|
|
1535
|
-
)
|
|
1559
|
+
test('multisig', () => {
|
|
1560
|
+
const tuple = KeyAuthorization.toTuple({
|
|
1561
|
+
address,
|
|
1562
|
+
chainId: 1n,
|
|
1563
|
+
signature: signature_multisig,
|
|
1564
|
+
type: 'secp256k1',
|
|
1565
|
+
})
|
|
1566
|
+
|
|
1567
|
+
expect(tuple[1]).toBe(SignatureEnvelope.serialize(signature_multisig))
|
|
1536
1568
|
})
|
|
1537
1569
|
|
|
1538
1570
|
test('default', () => {
|
|
@@ -2483,12 +2515,12 @@ describe('admin keys (TIP-1049)', () => {
|
|
|
2483
2515
|
expect(restored.account).toBeUndefined()
|
|
2484
2516
|
})
|
|
2485
2517
|
|
|
2486
|
-
test('fromTuple:
|
|
2518
|
+
test('fromTuple: preserves a non-admin account binding', () => {
|
|
2487
2519
|
const restored = KeyAuthorization.fromTuple([
|
|
2488
2520
|
['0x01', '0x', address, '0x', [], [], '0x', '0x', account],
|
|
2489
2521
|
])
|
|
2490
|
-
expect(restored.isAdmin).
|
|
2491
|
-
expect(restored.account).
|
|
2522
|
+
expect(restored.isAdmin).toBe(false)
|
|
2523
|
+
expect(restored.account).toBe(account)
|
|
2492
2524
|
})
|
|
2493
2525
|
|
|
2494
2526
|
test('fromTuple: extracts isAdmin + account together', () => {
|
|
@@ -2523,6 +2555,20 @@ describe('admin keys (TIP-1049)', () => {
|
|
|
2523
2555
|
expect(restored.account).toBe(account)
|
|
2524
2556
|
})
|
|
2525
2557
|
|
|
2558
|
+
test('serialize/deserialize: roundtrip with non-admin account binding', () => {
|
|
2559
|
+
const authorization = KeyAuthorization.from({
|
|
2560
|
+
address,
|
|
2561
|
+
account,
|
|
2562
|
+
chainId: 1n,
|
|
2563
|
+
isAdmin: false,
|
|
2564
|
+
type: 'secp256k1',
|
|
2565
|
+
})
|
|
2566
|
+
const serialized = KeyAuthorization.serialize(authorization)
|
|
2567
|
+
const restored = KeyAuthorization.deserialize(serialized)
|
|
2568
|
+
expect(restored.isAdmin).toBe(false)
|
|
2569
|
+
expect(restored.account).toBe(account)
|
|
2570
|
+
})
|
|
2571
|
+
|
|
2526
2572
|
test('toRpc/fromRpc: roundtrip with isAdmin + account', () => {
|
|
2527
2573
|
const authorization = KeyAuthorization.from(
|
|
2528
2574
|
{
|
|
@@ -2553,15 +2599,15 @@ describe('admin keys (TIP-1049)', () => {
|
|
|
2553
2599
|
expect(restored.account).toBeUndefined()
|
|
2554
2600
|
})
|
|
2555
2601
|
|
|
2556
|
-
test('fromRpc:
|
|
2602
|
+
test('fromRpc: preserves a non-admin account binding', () => {
|
|
2557
2603
|
const authorization = KeyAuthorization.from(
|
|
2558
2604
|
{ address, chainId: 1n, type: 'secp256k1' },
|
|
2559
2605
|
{ signature: SignatureEnvelope.from(signature_secp256k1) },
|
|
2560
2606
|
)
|
|
2561
2607
|
const rpc = KeyAuthorization.toRpc(authorization)
|
|
2562
2608
|
const restored = KeyAuthorization.fromRpc({ ...rpc, account })
|
|
2563
|
-
expect(restored.isAdmin).
|
|
2564
|
-
expect(restored.account).
|
|
2609
|
+
expect(restored.isAdmin).toBe(false)
|
|
2610
|
+
expect(restored.account).toBe(account)
|
|
2565
2611
|
})
|
|
2566
2612
|
|
|
2567
2613
|
test('hash: changes when admin pair is added', () => {
|
|
@@ -81,13 +81,22 @@ export type KeyAuthorization<
|
|
|
81
81
|
| {}
|
|
82
82
|
> &
|
|
83
83
|
(signed extends true
|
|
84
|
-
? { signature:
|
|
84
|
+
? { signature: Signature<bigintType, numberType> }
|
|
85
85
|
: {
|
|
86
|
-
signature?:
|
|
87
|
-
| SignatureEnvelope.Primitive<bigintType, numberType>
|
|
88
|
-
| undefined
|
|
86
|
+
signature?: Signature<bigintType, numberType> | undefined
|
|
89
87
|
})
|
|
90
88
|
|
|
89
|
+
/** Signature that can authorize an access key. */
|
|
90
|
+
export type Signature<bigintType = bigint, numberType = number> = OneOf<
|
|
91
|
+
| SignatureEnvelope.Primitive<bigintType, numberType>
|
|
92
|
+
| SignatureEnvelope.Multisig<bigintType, numberType>
|
|
93
|
+
>
|
|
94
|
+
|
|
95
|
+
/** RPC-formatted signature that can authorize an access key. */
|
|
96
|
+
export type SignatureRpc = OneOf<
|
|
97
|
+
SignatureEnvelope.PrimitiveRpc | SignatureEnvelope.MultisigRpc
|
|
98
|
+
>
|
|
99
|
+
|
|
91
100
|
/** Input type for a Key Authorization. */
|
|
92
101
|
export type Input = KeyAuthorization<
|
|
93
102
|
false,
|
|
@@ -114,8 +123,8 @@ export type Rpc = {
|
|
|
114
123
|
keyType: SignatureEnvelope.Type
|
|
115
124
|
/** Token spending limits. */
|
|
116
125
|
limits?: readonly RpcTokenLimit[] | undefined
|
|
117
|
-
/**
|
|
118
|
-
signature:
|
|
126
|
+
/** Signature authorizing this key. */
|
|
127
|
+
signature: SignatureRpc
|
|
119
128
|
/** Optional 32-byte witness (hex). */
|
|
120
129
|
witness?: Hex.Hex | null | undefined
|
|
121
130
|
}
|
|
@@ -146,10 +155,11 @@ export type Signed<
|
|
|
146
155
|
addressType = Address.Address,
|
|
147
156
|
> = KeyAuthorization<true, bigintType, numberType, addressType>
|
|
148
157
|
|
|
149
|
-
type
|
|
150
|
-
| UnionPartialBy<
|
|
158
|
+
type SignatureValue =
|
|
159
|
+
| UnionPartialBy<Signature, 'prehash' | 'type'>
|
|
151
160
|
| SignatureEnvelope.Secp256k1Flat
|
|
152
161
|
| SignatureEnvelope.Serialized
|
|
162
|
+
| SignatureEnvelope.from.MultisigFromInitialConfig
|
|
153
163
|
|
|
154
164
|
type BaseTuple = readonly [
|
|
155
165
|
chainId: Hex.Hex,
|
|
@@ -408,7 +418,7 @@ export type TokenLimit<
|
|
|
408
418
|
*/
|
|
409
419
|
export function from<
|
|
410
420
|
const authorization extends Input | Rpc,
|
|
411
|
-
const signature extends
|
|
421
|
+
const signature extends SignatureValue | undefined = undefined,
|
|
412
422
|
>(
|
|
413
423
|
authorization: authorization | KeyAuthorization,
|
|
414
424
|
options: from.Options<signature> = {},
|
|
@@ -467,29 +477,25 @@ export function from<
|
|
|
467
477
|
|
|
468
478
|
export declare namespace from {
|
|
469
479
|
type Options<
|
|
470
|
-
signature extends
|
|
471
|
-
| PrimitiveSignatureValue
|
|
472
|
-
| undefined,
|
|
480
|
+
signature extends SignatureValue | undefined = SignatureValue | undefined,
|
|
473
481
|
> = {
|
|
474
|
-
/** The
|
|
475
|
-
signature?: signature |
|
|
482
|
+
/** The signature to attach to the Key Authorization. */
|
|
483
|
+
signature?: signature | Signature | undefined
|
|
476
484
|
}
|
|
477
485
|
|
|
478
486
|
type ReturnType<
|
|
479
487
|
authorization extends KeyAuthorization | Input | Rpc = KeyAuthorization,
|
|
480
|
-
signature extends
|
|
481
|
-
| PrimitiveSignatureValue
|
|
482
|
-
| undefined,
|
|
488
|
+
signature extends SignatureValue | undefined = SignatureValue | undefined,
|
|
483
489
|
> = Compute<
|
|
484
490
|
authorization extends Rpc
|
|
485
491
|
? Signed
|
|
486
492
|
: TempoAddress.ResolveAddresses<
|
|
487
493
|
authorization &
|
|
488
|
-
(signature extends
|
|
494
|
+
(signature extends SignatureValue
|
|
489
495
|
? {
|
|
490
496
|
signature: Extract<
|
|
491
497
|
SignatureEnvelope.from.ReturnValue<signature>,
|
|
492
|
-
|
|
498
|
+
Signature
|
|
493
499
|
>
|
|
494
500
|
}
|
|
495
501
|
: {})
|
|
@@ -551,11 +557,8 @@ export function fromRpc(authorization: Rpc): Signed {
|
|
|
551
557
|
})
|
|
552
558
|
: undefined
|
|
553
559
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
// assignability without `exactOptionalPropertyTypes` (#290).
|
|
557
|
-
const adminPair =
|
|
558
|
-
account !== undefined && isAdmin ? { account, isAdmin: true as const } : {}
|
|
560
|
+
const accountBinding =
|
|
561
|
+
account !== undefined ? { account, isAdmin: isAdmin ?? false } : {}
|
|
559
562
|
|
|
560
563
|
return {
|
|
561
564
|
address: keyId,
|
|
@@ -572,7 +575,7 @@ export function fromRpc(authorization: Rpc): Signed {
|
|
|
572
575
|
signature,
|
|
573
576
|
type: keyType,
|
|
574
577
|
...(witness !== undefined ? { witness } : {}),
|
|
575
|
-
...
|
|
578
|
+
...accountBinding,
|
|
576
579
|
}
|
|
577
580
|
}
|
|
578
581
|
|
|
@@ -694,11 +697,8 @@ export function fromTuple<const tuple extends Tuple>(
|
|
|
694
697
|
const account = isAbsent(rawAccount)
|
|
695
698
|
? undefined
|
|
696
699
|
: (rawAccount as Address.Address)
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
// but the orphan field is dropped (since the public API requires both).
|
|
700
|
-
const adminPair =
|
|
701
|
-
account !== undefined && isAdmin ? { account, isAdmin: true as const } : {}
|
|
700
|
+
const accountBinding =
|
|
701
|
+
account !== undefined ? { account, isAdmin: isAdmin ?? false } : {}
|
|
702
702
|
const args: KeyAuthorization = {
|
|
703
703
|
address: keyId,
|
|
704
704
|
chainId: chainId === '0x' ? 0n : Hex.toBigInt(chainId),
|
|
@@ -707,7 +707,7 @@ export function fromTuple<const tuple extends Tuple>(
|
|
|
707
707
|
...(limits !== undefined ? { limits } : {}),
|
|
708
708
|
...(scopes !== undefined ? { scopes } : {}),
|
|
709
709
|
...(witness !== undefined ? { witness } : {}),
|
|
710
|
-
...
|
|
710
|
+
...accountBinding,
|
|
711
711
|
}
|
|
712
712
|
if (signatureSerialized) {
|
|
713
713
|
const signature = SignatureEnvelope.deserialize(signatureSerialized)
|
|
@@ -963,9 +963,7 @@ export function toRpc(authorization: Signed): Rpc {
|
|
|
963
963
|
limit: Hex.fromNumber(limit),
|
|
964
964
|
...(period ? { period: numberToHex(period) } : {}),
|
|
965
965
|
})),
|
|
966
|
-
signature: SignatureEnvelope.toRpc(
|
|
967
|
-
signature,
|
|
968
|
-
) as SignatureEnvelope.PrimitiveRpc,
|
|
966
|
+
signature: SignatureEnvelope.toRpc(signature) as SignatureRpc,
|
|
969
967
|
...(allowedCalls ? { allowedCalls } : {}),
|
|
970
968
|
...(witness !== undefined ? { witness } : {}),
|
|
971
969
|
...(isAdmin ? { isAdmin: true } : {}),
|
|
@@ -1162,8 +1160,8 @@ function assertWitness(witness: Hex.Hex): void {
|
|
|
1162
1160
|
|
|
1163
1161
|
function assertSignature<bigintType, numberType>(
|
|
1164
1162
|
signature: SignatureEnvelope.SignatureEnvelope<bigintType, numberType>,
|
|
1165
|
-
): asserts signature is
|
|
1166
|
-
if (signature.type === 'keychain'
|
|
1163
|
+
): asserts signature is Signature<bigintType, numberType> {
|
|
1164
|
+
if (signature.type === 'keychain')
|
|
1167
1165
|
throw new InvalidSignatureTypeError(signature.type)
|
|
1168
1166
|
}
|
|
1169
1167
|
|
|
@@ -1191,12 +1189,12 @@ export class InvalidAdminMarkerError extends Error {
|
|
|
1191
1189
|
}
|
|
1192
1190
|
}
|
|
1193
1191
|
|
|
1194
|
-
/** Thrown when a key authorization contains a
|
|
1192
|
+
/** Thrown when a key authorization contains a keychain signature. */
|
|
1195
1193
|
export class InvalidSignatureTypeError extends Error {
|
|
1196
1194
|
override readonly name = 'KeyAuthorization.InvalidSignatureTypeError'
|
|
1197
1195
|
constructor(type: SignatureEnvelope.SignatureEnvelope['type']) {
|
|
1198
1196
|
super(
|
|
1199
|
-
`Signature type \`${type}\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, or \`
|
|
1197
|
+
`Signature type \`${type}\` is invalid for key authorizations; expected \`secp256k1\`, \`p256\`, \`webAuthn\`, or \`multisig\`.`,
|
|
1200
1198
|
)
|
|
1201
1199
|
}
|
|
1202
1200
|
}
|
|
@@ -86,24 +86,44 @@ describe('getSignPayload', () => {
|
|
|
86
86
|
test('matches independent ground truth', () => {
|
|
87
87
|
expect(
|
|
88
88
|
MultisigConfig.getSignPayload({
|
|
89
|
-
payload: `0x${'
|
|
90
|
-
|
|
89
|
+
payload: `0x${'42'.repeat(32)}`,
|
|
90
|
+
initialConfig: singleOwnerConfig,
|
|
91
91
|
}),
|
|
92
92
|
).toMatchInlineSnapshot(
|
|
93
|
-
`"
|
|
93
|
+
`"0xbf944a7a752b2cfab0418d5fb4591c5a7ff62976488edce11794d7f35fb34f41"`,
|
|
94
94
|
)
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
test('behavior: `
|
|
97
|
+
test('behavior: `initialConfig` and `{ account }` produce identical digests', () => {
|
|
98
98
|
const account = MultisigConfig.getAddress(singleOwnerConfig)
|
|
99
99
|
const payload = `0x${'42'.repeat(32)}` as const
|
|
100
100
|
expect(
|
|
101
101
|
MultisigConfig.getSignPayload({
|
|
102
102
|
payload,
|
|
103
|
-
|
|
103
|
+
initialConfig: singleOwnerConfig,
|
|
104
104
|
}),
|
|
105
105
|
).toBe(MultisigConfig.getSignPayload({ payload, account }))
|
|
106
106
|
})
|
|
107
|
+
|
|
108
|
+
test('differs for a different config version', () => {
|
|
109
|
+
const value = {
|
|
110
|
+
payload: `0x${'42'.repeat(32)}` as const,
|
|
111
|
+
initialConfig: singleOwnerConfig,
|
|
112
|
+
}
|
|
113
|
+
expect(MultisigConfig.getSignPayload(value)).not.toBe(
|
|
114
|
+
MultisigConfig.getSignPayload({ ...value, version: 1n }),
|
|
115
|
+
)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test('defaults the config version to zero', () => {
|
|
119
|
+
const value = {
|
|
120
|
+
payload: `0x${'42'.repeat(32)}` as const,
|
|
121
|
+
initialConfig: singleOwnerConfig,
|
|
122
|
+
}
|
|
123
|
+
expect(MultisigConfig.getSignPayload(value)).toBe(
|
|
124
|
+
MultisigConfig.getSignPayload({ ...value, version: 0n }),
|
|
125
|
+
)
|
|
126
|
+
})
|
|
107
127
|
})
|
|
108
128
|
|
|
109
129
|
describe('toTuple / fromTuple', () => {
|
|
@@ -149,8 +169,8 @@ describe('assert / validate', () => {
|
|
|
149
169
|
expect(MultisigConfig.validate({ threshold: 1, owners: [] })).toBe(false)
|
|
150
170
|
})
|
|
151
171
|
|
|
152
|
-
test('accepts
|
|
153
|
-
const owners = Array.from({ length:
|
|
172
|
+
test('accepts 50 owners', () => {
|
|
173
|
+
const owners = Array.from({ length: 50 }, (_, i) => ({
|
|
154
174
|
owner: `0x${(i + 1).toString(16).padStart(40, '0')}` as `0x${string}`,
|
|
155
175
|
weight: 1,
|
|
156
176
|
}))
|
|
@@ -163,7 +183,7 @@ describe('assert / validate', () => {
|
|
|
163
183
|
})
|
|
164
184
|
|
|
165
185
|
test('too many owners', () => {
|
|
166
|
-
const owners = Array.from({ length:
|
|
186
|
+
const owners = Array.from({ length: 51 }, (_, i) => ({
|
|
167
187
|
owner: `0x${(i + 1).toString(16).padStart(40, '0')}` as `0x${string}`,
|
|
168
188
|
weight: 1,
|
|
169
189
|
}))
|