ox 1.7.0 → 1.7.2
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 +21 -0
- package/dist/core/Hash.js +1 -1
- package/dist/core/Hash.js.map +1 -1
- package/dist/core/Siwe.d.ts.map +1 -1
- package/dist/core/Siwe.js +45 -6
- package/dist/core/Siwe.js.map +1 -1
- package/dist/tempo/KeyAuthorization.d.ts +1 -1
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/MultisigConfig.d.ts +151 -83
- package/dist/tempo/MultisigConfig.d.ts.map +1 -1
- package/dist/tempo/MultisigConfig.js +164 -86
- package/dist/tempo/MultisigConfig.js.map +1 -1
- package/dist/tempo/MultisigOperation.d.ts +324 -0
- package/dist/tempo/MultisigOperation.d.ts.map +1 -0
- package/dist/tempo/MultisigOperation.js +809 -0
- package/dist/tempo/MultisigOperation.js.map +1 -0
- package/dist/tempo/MultisigWitness.d.ts +106 -0
- package/dist/tempo/MultisigWitness.d.ts.map +1 -0
- package/dist/tempo/MultisigWitness.js +118 -0
- package/dist/tempo/MultisigWitness.js.map +1 -0
- package/dist/tempo/RpcSchemaTempo.d.ts +35 -0
- package/dist/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +60 -80
- package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/tempo/SignatureEnvelope.js +87 -146
- package/dist/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/tempo/TransactionRequest.d.ts +9 -17
- package/dist/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/tempo/TransactionRequest.js +7 -7
- package/dist/tempo/TransactionRequest.js.map +1 -1
- package/dist/tempo/TxEnvelopeTempo.d.ts +3 -2
- package/dist/tempo/TxEnvelopeTempo.d.ts.map +1 -1
- package/dist/tempo/TxEnvelopeTempo.js +3 -2
- package/dist/tempo/TxEnvelopeTempo.js.map +1 -1
- package/dist/tempo/index.d.ts +22 -2
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +22 -2
- package/dist/tempo/index.js.map +1 -1
- package/dist/zod/tempo/AuthorizationTempo.d.ts +110 -110
- package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
- package/dist/zod/tempo/KeyAuthorization.d.ts +90 -83
- package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/zod/tempo/MultisigConfig.d.ts +31 -2
- package/dist/zod/tempo/MultisigConfig.d.ts.map +1 -1
- package/dist/zod/tempo/MultisigConfig.js +26 -3
- package/dist/zod/tempo/MultisigConfig.js.map +1 -1
- package/dist/zod/tempo/MultisigOperation.d.ts +168 -0
- package/dist/zod/tempo/MultisigOperation.d.ts.map +1 -0
- package/dist/zod/tempo/MultisigOperation.js +65 -0
- package/dist/zod/tempo/MultisigOperation.js.map +1 -0
- package/dist/zod/tempo/MultisigWitness.d.ts +152 -0
- package/dist/zod/tempo/MultisigWitness.d.ts.map +1 -0
- package/dist/zod/tempo/MultisigWitness.js +76 -0
- package/dist/zod/tempo/MultisigWitness.js.map +1 -0
- package/dist/zod/tempo/RpcSchemaTempo.d.ts +607 -102
- package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/dist/zod/tempo/RpcSchemaTempo.js +38 -0
- package/dist/zod/tempo/RpcSchemaTempo.js.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.d.ts +33 -33
- package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/dist/zod/tempo/SignatureEnvelope.js +9 -16
- package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
- package/dist/zod/tempo/Transaction.d.ts +228 -222
- package/dist/zod/tempo/Transaction.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.d.ts +379 -176
- package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
- package/dist/zod/tempo/TransactionRequest.js +11 -22
- package/dist/zod/tempo/TransactionRequest.js.map +1 -1
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts +60 -48
- package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
- package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +15 -12
- package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
- package/dist/zod/tempo/z.d.ts +2 -0
- package/dist/zod/tempo/z.d.ts.map +1 -1
- package/dist/zod/tempo/z.js +2 -0
- package/dist/zod/tempo/z.js.map +1 -1
- package/package.json +21 -1
- package/src/core/Hash.ts +1 -1
- package/src/core/Siwe.ts +45 -5
- package/src/core/_test/Hash.test.ts +15 -0
- package/src/core/_test/Siwe.test.ts +98 -0
- package/src/tempo/KeyAuthorization.test-d.ts +13 -1
- package/src/tempo/KeyAuthorization.test.ts +65 -0
- package/src/tempo/KeyAuthorization.ts +1 -1
- package/src/tempo/MultisigConfig.test-d.ts +52 -0
- package/src/tempo/MultisigConfig.test.ts +288 -227
- package/src/tempo/MultisigConfig.ts +275 -104
- package/src/tempo/MultisigOperation.test-d.ts +77 -0
- package/src/tempo/MultisigOperation.test.ts +1883 -0
- package/src/tempo/MultisigOperation.ts +1254 -0
- package/src/tempo/MultisigWitness.test-d.ts +42 -0
- package/src/tempo/MultisigWitness.test.ts +288 -0
- package/src/tempo/MultisigWitness.ts +210 -0
- package/src/tempo/RpcSchemaTempo.test-d.ts +56 -0
- package/src/tempo/RpcSchemaTempo.ts +37 -0
- package/src/tempo/SignatureEnvelope.test-d.ts +63 -46
- package/src/tempo/SignatureEnvelope.test.ts +523 -500
- package/src/tempo/SignatureEnvelope.ts +172 -242
- package/src/tempo/TransactionRequest.test-d.ts +11 -0
- package/src/tempo/TransactionRequest.test.ts +285 -33
- package/src/tempo/TransactionRequest.ts +15 -20
- package/src/tempo/TxEnvelopeTempo.test-d.ts +7 -0
- package/src/tempo/TxEnvelopeTempo.test.ts +25 -0
- package/src/tempo/TxEnvelopeTempo.ts +5 -3
- package/src/tempo/index.ts +22 -2
- package/src/tempo/multisig.e2e.test.ts +113 -86
- package/src/version.ts +1 -1
- package/src/zod/tempo/MultisigConfig.ts +29 -3
- package/src/zod/tempo/MultisigOperation.ts +69 -0
- package/src/zod/tempo/MultisigWitness.ts +101 -0
- package/src/zod/tempo/RpcSchemaTempo.ts +43 -0
- package/src/zod/tempo/SignatureEnvelope.ts +20 -38
- package/src/zod/tempo/TransactionRequest.ts +17 -26
- package/src/zod/tempo/_test/KeyAuthorization.test.ts +11 -0
- package/src/zod/tempo/_test/MultisigConfig.test-d.ts +13 -0
- package/src/zod/tempo/_test/MultisigConfig.test.ts +13 -2
- package/src/zod/tempo/_test/MultisigOperation.test-d.ts +27 -0
- package/src/zod/tempo/_test/MultisigOperation.test.ts +68 -0
- package/src/zod/tempo/_test/MultisigWitness.test-d.ts +13 -0
- package/src/zod/tempo/_test/MultisigWitness.test.ts +149 -0
- package/src/zod/tempo/_test/RpcSchemaTempo.test-d.ts +31 -0
- package/src/zod/tempo/_test/RpcSchemaTempo.test.ts +41 -0
- package/src/zod/tempo/_test/SignatureEnvelope.test-d.ts +1 -1
- package/src/zod/tempo/_test/SignatureEnvelope.test.ts +25 -34
- package/src/zod/tempo/_test/TransactionRequest.test.ts +176 -8
- package/src/zod/tempo/z.ts +2 -0
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
IsNarrowable,
|
|
9
9
|
OneOf,
|
|
10
10
|
PartialBy,
|
|
11
|
+
Undefined,
|
|
11
12
|
UnionPartialBy,
|
|
12
13
|
} from '../core/internal/types.js'
|
|
13
14
|
import * as Json from '../core/Json.js'
|
|
@@ -27,6 +28,15 @@ const serializedKeychainType = '0x03'
|
|
|
27
28
|
const serializedKeychainV2Type = '0x04'
|
|
28
29
|
const serializedMultisigType = '0x05'
|
|
29
30
|
|
|
31
|
+
type NonMultisig<numberType = number> = OneOf<
|
|
32
|
+
| Secp256k1<numberType>
|
|
33
|
+
| P256<numberType>
|
|
34
|
+
| WebAuthn<numberType>
|
|
35
|
+
| Keychain<numberType>
|
|
36
|
+
>
|
|
37
|
+
|
|
38
|
+
type NonMultisigRpc = OneOf<Secp256k1Rpc | P256Rpc | WebAuthnRpc | KeychainRpc>
|
|
39
|
+
|
|
30
40
|
/** Serialized magic identifier for Tempo signature envelopes. */
|
|
31
41
|
export const magicBytes =
|
|
32
42
|
'0x7777777777777777777777777777777777777777777777777777777777777777' // 32 "T"s
|
|
@@ -84,15 +94,7 @@ export type GetType<
|
|
|
84
94
|
userAddress: Address.Address
|
|
85
95
|
}
|
|
86
96
|
? 'keychain'
|
|
87
|
-
: envelope extends
|
|
88
|
-
| {
|
|
89
|
-
account: Address.Address
|
|
90
|
-
signatures: any
|
|
91
|
-
}
|
|
92
|
-
| {
|
|
93
|
-
init: MultisigConfig.Config
|
|
94
|
-
signatures: any
|
|
95
|
-
}
|
|
97
|
+
: envelope extends { config: unknown; signatures: any }
|
|
96
98
|
? 'multisig'
|
|
97
99
|
: never
|
|
98
100
|
|
|
@@ -119,20 +121,14 @@ export type GetType<
|
|
|
119
121
|
*
|
|
120
122
|
* [Signature Types Specification](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types)
|
|
121
123
|
*/
|
|
122
|
-
export type SignatureEnvelope<numberType = number> =
|
|
123
|
-
|
|
|
124
|
-
|
|
|
125
|
-
| WebAuthn<numberType>
|
|
126
|
-
| Keychain<numberType>
|
|
127
|
-
| Multisig<numberType>
|
|
128
|
-
>
|
|
124
|
+
export type SignatureEnvelope<numberType = number> =
|
|
125
|
+
| (NonMultisig<numberType> & Undefined<Omit<Multisig<numberType>, 'type'>>)
|
|
126
|
+
| MultisigOneOf<numberType>
|
|
129
127
|
|
|
130
|
-
/**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Secp256k1Rpc | P256Rpc | WebAuthnRpc | KeychainRpc | MultisigRpc
|
|
135
|
-
>
|
|
128
|
+
/** RPC-formatted signature envelope. */
|
|
129
|
+
export type SignatureEnvelopeRpc =
|
|
130
|
+
| (NonMultisigRpc & Undefined<Omit<MultisigRpc, 'type'>>)
|
|
131
|
+
| MultisigRpcOneOf
|
|
136
132
|
|
|
137
133
|
/** Primitive signature envelope accepted by protocol sidecars. */
|
|
138
134
|
export type Primitive<numberType = number> = OneOf<
|
|
@@ -182,42 +178,38 @@ export type KeychainRpc = {
|
|
|
182
178
|
* [TIP-1061](https://tips.sh/1061)
|
|
183
179
|
*/
|
|
184
180
|
export type Multisig<numberType = number> = {
|
|
185
|
-
type: 'multisig'
|
|
186
181
|
/** Native multisig account address. */
|
|
187
182
|
account: Address.Address
|
|
183
|
+
/** Complete applicable multisig configuration witness. */
|
|
184
|
+
config: MultisigConfig.Config<bigint, numberType>
|
|
188
185
|
/**
|
|
189
186
|
* Owner approvals over the multisig owner approval digest. Each approval is
|
|
190
187
|
* either a primitive signature or a nested multisig signature (keychain
|
|
191
188
|
* approvals are invalid).
|
|
192
189
|
*/
|
|
193
190
|
signatures: readonly SignatureEnvelope<numberType>[]
|
|
194
|
-
|
|
195
|
-
* Initial native multisig config for bootstrapping this account. Present only on
|
|
196
|
-
* the first (bootstrap) transaction from the derived account; absent on every
|
|
197
|
-
* subsequent transaction.
|
|
198
|
-
*/
|
|
199
|
-
init?: MultisigConfig.Config<numberType> | undefined
|
|
191
|
+
type: 'multisig'
|
|
200
192
|
}
|
|
201
193
|
|
|
194
|
+
interface MultisigOneOf<numberType = number>
|
|
195
|
+
extends
|
|
196
|
+
Multisig<numberType>,
|
|
197
|
+
Undefined<Omit<NonMultisig<numberType>, 'type'>> {}
|
|
198
|
+
|
|
202
199
|
/** RPC-formatted native multisig signature. */
|
|
203
|
-
export type MultisigRpc =
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
signatures: readonly SignatureEnvelopeRpc[]
|
|
217
|
-
/** Multisig RPC signatures are untagged. */
|
|
218
|
-
type?: undefined
|
|
219
|
-
}
|
|
220
|
-
>
|
|
200
|
+
export type MultisigRpc = {
|
|
201
|
+
/** Native multisig account address. */
|
|
202
|
+
account: Address.Address
|
|
203
|
+
/** Complete applicable multisig configuration witness. */
|
|
204
|
+
config: MultisigConfig.Rpc
|
|
205
|
+
/** Structured owner approvals. */
|
|
206
|
+
signatures: readonly SignatureEnvelopeRpc[]
|
|
207
|
+
/** Multisig RPC signatures are untagged. */
|
|
208
|
+
type?: undefined
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface MultisigRpcOneOf
|
|
212
|
+
extends MultisigRpc, Undefined<Omit<NonMultisigRpc, 'type'>> {}
|
|
221
213
|
|
|
222
214
|
export type P256<numberType = number> = {
|
|
223
215
|
prehash: boolean
|
|
@@ -380,6 +372,7 @@ export declare namespace assert {
|
|
|
380
372
|
function assertMultisig(envelope: Multisig, depth: number): void {
|
|
381
373
|
const missing: string[] = []
|
|
382
374
|
if (!envelope.account) missing.push('account')
|
|
375
|
+
if (!envelope.config) missing.push('config')
|
|
383
376
|
if (!Array.isArray(envelope.signatures)) missing.push('signatures')
|
|
384
377
|
if (missing.length > 0)
|
|
385
378
|
throw new MissingPropertiesError({
|
|
@@ -399,6 +392,25 @@ function assertMultisig(envelope: Multisig, depth: number): void {
|
|
|
399
392
|
throw new InvalidMultisigApprovalError({
|
|
400
393
|
reason: 'multisig account cannot be zero',
|
|
401
394
|
})
|
|
395
|
+
MultisigConfig.assert(envelope.config)
|
|
396
|
+
if (
|
|
397
|
+
envelope.config.owners.some((owner) =>
|
|
398
|
+
Address.isEqual(owner.owner, envelope.account),
|
|
399
|
+
)
|
|
400
|
+
)
|
|
401
|
+
throw new InvalidMultisigApprovalError({
|
|
402
|
+
reason: 'multisig account cannot be an owner',
|
|
403
|
+
})
|
|
404
|
+
if (
|
|
405
|
+
envelope.config.version === 0n &&
|
|
406
|
+
!Address.isEqual(
|
|
407
|
+
MultisigConfig.getAddress(envelope.config),
|
|
408
|
+
envelope.account,
|
|
409
|
+
)
|
|
410
|
+
)
|
|
411
|
+
throw new InvalidMultisigApprovalError({
|
|
412
|
+
reason: 'initial multisig config does not derive account',
|
|
413
|
+
})
|
|
402
414
|
if (envelope.signatures.length === 0)
|
|
403
415
|
throw new InvalidMultisigApprovalError({
|
|
404
416
|
reason: 'multisig signatures cannot be empty',
|
|
@@ -408,33 +420,14 @@ function assertMultisig(envelope: Multisig, depth: number): void {
|
|
|
408
420
|
reason: `multisig signatures exceed ${MultisigConfig.maxSignatures}`,
|
|
409
421
|
})
|
|
410
422
|
|
|
411
|
-
if (envelope.init) {
|
|
412
|
-
MultisigConfig.assert(envelope.init)
|
|
413
|
-
if (
|
|
414
|
-
!Address.isEqual(
|
|
415
|
-
MultisigConfig.getAddress(envelope.init),
|
|
416
|
-
envelope.account,
|
|
417
|
-
)
|
|
418
|
-
)
|
|
419
|
-
throw new InvalidMultisigApprovalError({
|
|
420
|
-
reason: 'multisig init does not derive account',
|
|
421
|
-
})
|
|
422
|
-
}
|
|
423
|
-
|
|
424
423
|
for (const inner of envelope.signatures) {
|
|
425
424
|
const type = getType(inner)
|
|
426
425
|
if (type === 'keychain')
|
|
427
426
|
throw new InvalidMultisigApprovalError({
|
|
428
427
|
reason: 'keychain owner approvals are not allowed',
|
|
429
428
|
})
|
|
430
|
-
if (type === 'multisig')
|
|
431
|
-
|
|
432
|
-
if (multisig.init)
|
|
433
|
-
throw new InvalidMultisigApprovalError({
|
|
434
|
-
reason: 'nested multisig owner approvals cannot carry `init`',
|
|
435
|
-
})
|
|
436
|
-
assertMultisig(multisig, depth + 1)
|
|
437
|
-
} else {
|
|
429
|
+
if (type === 'multisig') assertMultisig(inner as Multisig, depth + 1)
|
|
430
|
+
else {
|
|
438
431
|
assert(inner)
|
|
439
432
|
if (Hex.size(serialize(inner)) > MultisigConfig.maxOwnerSignatureBytes)
|
|
440
433
|
throw new InvalidMultisigApprovalError({
|
|
@@ -724,16 +717,48 @@ function deserialize_(
|
|
|
724
717
|
serialized,
|
|
725
718
|
})
|
|
726
719
|
|
|
727
|
-
// The first field distinguishes the static wire shapes: a bootstrap init
|
|
728
|
-
// config is an RLP list, while an initialized account is a 20-byte string.
|
|
729
720
|
const decoded = Rlp.toHex(data)
|
|
730
|
-
if (!Array.isArray(decoded) || decoded.length !==
|
|
721
|
+
if (!Array.isArray(decoded) || decoded.length !== 3)
|
|
731
722
|
throw new InvalidSerializedError({
|
|
732
|
-
reason: 'invalid multisig wire shape: expected exactly
|
|
723
|
+
reason: 'invalid multisig wire shape: expected exactly three fields',
|
|
733
724
|
serialized,
|
|
734
725
|
})
|
|
735
726
|
|
|
736
|
-
const [
|
|
727
|
+
const [account, config, signatures] = decoded
|
|
728
|
+
if (!Address.validate(account))
|
|
729
|
+
throw new InvalidSerializedError({
|
|
730
|
+
reason: 'invalid multisig account',
|
|
731
|
+
serialized,
|
|
732
|
+
})
|
|
733
|
+
if (!Array.isArray(config))
|
|
734
|
+
throw new InvalidSerializedError({
|
|
735
|
+
reason: 'invalid multisig config',
|
|
736
|
+
serialized,
|
|
737
|
+
})
|
|
738
|
+
const [salt, version, threshold, owners] = config
|
|
739
|
+
if (
|
|
740
|
+
config.length !== 4 ||
|
|
741
|
+
Array.isArray(salt) ||
|
|
742
|
+
Hex.size(salt) !== 32 ||
|
|
743
|
+
Array.isArray(version) ||
|
|
744
|
+
Hex.size(version) > 8 ||
|
|
745
|
+
(version !== '0x' && Hex.slice(version, 0, 1) === '0x00') ||
|
|
746
|
+
Array.isArray(threshold) ||
|
|
747
|
+
Hex.size(threshold) > 1 ||
|
|
748
|
+
!Array.isArray(owners) ||
|
|
749
|
+
owners.some(
|
|
750
|
+
(owner) =>
|
|
751
|
+
!Array.isArray(owner) ||
|
|
752
|
+
owner.length !== 2 ||
|
|
753
|
+
owner.some(Array.isArray) ||
|
|
754
|
+
!Address.validate(owner[0]) ||
|
|
755
|
+
Hex.size(owner[1] as Hex.Hex) > 1,
|
|
756
|
+
)
|
|
757
|
+
)
|
|
758
|
+
throw new InvalidSerializedError({
|
|
759
|
+
reason: 'invalid multisig config',
|
|
760
|
+
serialized,
|
|
761
|
+
})
|
|
737
762
|
if (!Array.isArray(signatures) || signatures.some(Array.isArray))
|
|
738
763
|
throw new InvalidSerializedError({
|
|
739
764
|
reason: 'invalid multisig signatures list',
|
|
@@ -761,47 +786,15 @@ function deserialize_(
|
|
|
761
786
|
serialized,
|
|
762
787
|
})
|
|
763
788
|
|
|
764
|
-
if (!Array.isArray(address) && !Address.validate(address))
|
|
765
|
-
throw new InvalidSerializedError({
|
|
766
|
-
reason: 'invalid multisig account',
|
|
767
|
-
serialized,
|
|
768
|
-
})
|
|
769
|
-
if (Array.isArray(address)) {
|
|
770
|
-
const [salt, threshold, owners] = address
|
|
771
|
-
if (
|
|
772
|
-
address.length !== 3 ||
|
|
773
|
-
Array.isArray(salt) ||
|
|
774
|
-
Hex.size(salt) !== 32 ||
|
|
775
|
-
Array.isArray(threshold) ||
|
|
776
|
-
Hex.size(threshold) > 1 ||
|
|
777
|
-
!Array.isArray(owners) ||
|
|
778
|
-
owners.some(
|
|
779
|
-
(owner) =>
|
|
780
|
-
!Array.isArray(owner) ||
|
|
781
|
-
owner.length !== 2 ||
|
|
782
|
-
owner.some(Array.isArray) ||
|
|
783
|
-
Hex.size(owner[1] as Hex.Hex) > 1,
|
|
784
|
-
)
|
|
785
|
-
)
|
|
786
|
-
throw new InvalidSerializedError({
|
|
787
|
-
reason: 'invalid multisig init config',
|
|
788
|
-
serialized,
|
|
789
|
-
})
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
const init = Array.isArray(address)
|
|
793
|
-
? MultisigConfig.fromTuple(address as unknown as MultisigConfig.Tuple)
|
|
794
|
-
: undefined
|
|
795
|
-
const account = init
|
|
796
|
-
? MultisigConfig.getAddress(init)
|
|
797
|
-
: (address as Address.Address)
|
|
798
789
|
const envelope = {
|
|
799
|
-
|
|
800
|
-
|
|
790
|
+
account: account as Address.Address,
|
|
791
|
+
config: MultisigConfig.fromTuple(
|
|
792
|
+
config as unknown as MultisigConfig.Tuple,
|
|
793
|
+
),
|
|
801
794
|
signatures: signatures.map((signature) =>
|
|
802
795
|
deserialize_(signature as Hex.Hex, depth),
|
|
803
796
|
),
|
|
804
|
-
|
|
797
|
+
type: 'multisig',
|
|
805
798
|
} satisfies Multisig
|
|
806
799
|
assertMultisig(envelope, depth)
|
|
807
800
|
return envelope
|
|
@@ -939,24 +932,20 @@ function deserialize_(
|
|
|
939
932
|
* ```
|
|
940
933
|
*
|
|
941
934
|
* @example
|
|
942
|
-
* ### Multisig
|
|
943
|
-
*
|
|
944
|
-
* Pass `initialConfig` to derive `account` automatically. Set `init: true` to
|
|
945
|
-
* opt into bootstrap (uses `initialConfig` as the bootstrap `init`); omit
|
|
946
|
-
* `init` for subsequent (non-bootstrap) transactions.
|
|
935
|
+
* ### Multisig
|
|
947
936
|
*
|
|
948
937
|
* ```ts twoslash
|
|
949
938
|
* import { Secp256k1 } from 'ox'
|
|
950
939
|
* import { MultisigConfig, SignatureEnvelope } from 'ox/tempo'
|
|
951
940
|
*
|
|
952
|
-
* const
|
|
953
|
-
* threshold: 1,
|
|
941
|
+
* const config = MultisigConfig.from({
|
|
954
942
|
* owners: [
|
|
955
943
|
* {
|
|
956
944
|
* owner: '0x1111111111111111111111111111111111111111',
|
|
957
945
|
* weight: 1
|
|
958
946
|
* }
|
|
959
|
-
* ]
|
|
947
|
+
* ],
|
|
948
|
+
* threshold: 1
|
|
960
949
|
* })
|
|
961
950
|
*
|
|
962
951
|
* const privateKey = Secp256k1.randomPrivateKey()
|
|
@@ -964,16 +953,8 @@ function deserialize_(
|
|
|
964
953
|
* Secp256k1.sign({ payload: '0xdeadbeef', privateKey })
|
|
965
954
|
* )
|
|
966
955
|
*
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
* initialConfig,
|
|
970
|
-
* signatures: [signature],
|
|
971
|
-
* init: true
|
|
972
|
-
* })
|
|
973
|
-
*
|
|
974
|
-
* // Subsequent (non-bootstrap) transactions
|
|
975
|
-
* const subsequent = SignatureEnvelope.from({
|
|
976
|
-
* initialConfig,
|
|
956
|
+
* const multisig = SignatureEnvelope.from({
|
|
957
|
+
* config,
|
|
977
958
|
* signatures: [signature]
|
|
978
959
|
* })
|
|
979
960
|
* ```
|
|
@@ -999,30 +980,17 @@ export function from<const value extends from.Value>(
|
|
|
999
980
|
const type = getType(value)
|
|
1000
981
|
|
|
1001
982
|
if (type === 'multisig') {
|
|
1002
|
-
const multisig = value as
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
const { initialConfig, init, ...rest } = multisig
|
|
1007
|
-
// Derive `account` from `initialConfig` when not provided explicitly.
|
|
1008
|
-
const account = (() => {
|
|
1009
|
-
if (rest.account) return rest.account
|
|
1010
|
-
if (initialConfig) return MultisigConfig.getAddress(initialConfig)
|
|
1011
|
-
return rest.account
|
|
1012
|
-
})()
|
|
1013
|
-
// `init: true` opts into bootstrap using the supplied `initialConfig`.
|
|
1014
|
-
// Otherwise, `init` is treated as the explicit bootstrap config (or
|
|
1015
|
-
// omitted).
|
|
1016
|
-
const initSource = init === true ? initialConfig : init || undefined
|
|
1017
|
-
return {
|
|
1018
|
-
...rest,
|
|
983
|
+
const multisig = value as from.MultisigFromConfig
|
|
984
|
+
const config = MultisigConfig.from(multisig.config)
|
|
985
|
+
const account = multisig.account ?? MultisigConfig.getAddress(config)
|
|
986
|
+
const envelope = {
|
|
1019
987
|
account,
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
// in-memory envelope matches what `deserialize` reconstructs.
|
|
1023
|
-
...(initSource ? { init: MultisigConfig.from(initSource) } : {}),
|
|
988
|
+
config,
|
|
989
|
+
signatures: multisig.signatures.map((signature) => from(signature)),
|
|
1024
990
|
type,
|
|
1025
|
-
}
|
|
991
|
+
} satisfies Multisig
|
|
992
|
+
assert(envelope)
|
|
993
|
+
return envelope as never
|
|
1026
994
|
}
|
|
1027
995
|
|
|
1028
996
|
return {
|
|
@@ -1067,24 +1035,32 @@ export declare namespace from {
|
|
|
1067
1035
|
payload?: Hex.Hex | Bytes.Bytes | undefined
|
|
1068
1036
|
}
|
|
1069
1037
|
|
|
1070
|
-
/**
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1038
|
+
/** Multisig signature input with an optional derived initial account. */
|
|
1039
|
+
type MultisigFromConfig =
|
|
1040
|
+
| {
|
|
1041
|
+
/** Initial native multisig account, derived from config when omitted. */
|
|
1042
|
+
account?: Address.Address | undefined
|
|
1043
|
+
/** Initial version-0 multisig configuration witness. */
|
|
1044
|
+
config: MultisigConfig.Input<0 | 0n>
|
|
1045
|
+
/** Primitive or nested owner approvals. */
|
|
1046
|
+
signatures: readonly SignatureEnvelope[]
|
|
1047
|
+
type?: 'multisig' | undefined
|
|
1048
|
+
}
|
|
1049
|
+
| {
|
|
1050
|
+
/** Native multisig account. */
|
|
1051
|
+
account: Address.Address
|
|
1052
|
+
/** Complete applicable multisig configuration witness. */
|
|
1053
|
+
config: MultisigConfig.Input
|
|
1054
|
+
/** Primitive or nested owner approvals. */
|
|
1055
|
+
signatures: readonly SignatureEnvelope[]
|
|
1056
|
+
type?: 'multisig' | undefined
|
|
1057
|
+
}
|
|
1082
1058
|
|
|
1083
1059
|
type Value =
|
|
1084
1060
|
| UnionPartialBy<SignatureEnvelope, 'prehash' | 'type'>
|
|
1085
1061
|
| Secp256k1Flat
|
|
1086
1062
|
| Serialized
|
|
1087
|
-
|
|
|
1063
|
+
| MultisigFromConfig
|
|
1088
1064
|
|
|
1089
1065
|
type ReturnValue<value extends Value> = Compute<
|
|
1090
1066
|
OneOf<
|
|
@@ -1092,7 +1068,7 @@ export declare namespace from {
|
|
|
1092
1068
|
? SignatureEnvelope
|
|
1093
1069
|
: value extends Secp256k1Flat
|
|
1094
1070
|
? Secp256k1
|
|
1095
|
-
: value extends
|
|
1071
|
+
: value extends MultisigFromConfig
|
|
1096
1072
|
? Multisig
|
|
1097
1073
|
: IsNarrowable<value, SignatureEnvelope> extends true
|
|
1098
1074
|
? SignatureEnvelope
|
|
@@ -1211,24 +1187,14 @@ export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
|
|
|
1211
1187
|
|
|
1212
1188
|
if (
|
|
1213
1189
|
(envelope as { type?: string | undefined }).type === 'multisig' ||
|
|
1214
|
-
('
|
|
1190
|
+
('config' in envelope && 'signatures' in envelope)
|
|
1215
1191
|
) {
|
|
1216
1192
|
const multisig = envelope as MultisigRpc
|
|
1217
|
-
const hasAccount = typeof multisig.account !== 'undefined'
|
|
1218
|
-
const hasInit = typeof multisig.init !== 'undefined'
|
|
1219
|
-
if (hasAccount === hasInit)
|
|
1220
|
-
throw new InvalidMultisigApprovalError({
|
|
1221
|
-
reason: 'RPC multisig must contain exactly one of `account` or `init`',
|
|
1222
|
-
})
|
|
1223
|
-
const init = hasInit
|
|
1224
|
-
? MultisigConfig.from(multisig.init as MultisigConfig.Config)
|
|
1225
|
-
: undefined
|
|
1226
|
-
const account = init ? MultisigConfig.getAddress(init) : multisig.account
|
|
1227
1193
|
const result = {
|
|
1228
|
-
|
|
1229
|
-
|
|
1194
|
+
account: multisig.account,
|
|
1195
|
+
config: MultisigConfig.fromRpc(multisig.config),
|
|
1230
1196
|
signatures: multisig.signatures.map((signature) => fromRpc(signature)),
|
|
1231
|
-
|
|
1197
|
+
type: 'multisig',
|
|
1232
1198
|
} satisfies Multisig
|
|
1233
1199
|
assert(result)
|
|
1234
1200
|
return result
|
|
@@ -1242,7 +1208,7 @@ export declare namespace fromRpc {
|
|
|
1242
1208
|
| assert.ErrorType
|
|
1243
1209
|
| CoercionError
|
|
1244
1210
|
| InvalidSerializedError
|
|
1245
|
-
| MultisigConfig.
|
|
1211
|
+
| MultisigConfig.fromRpc.ErrorType
|
|
1246
1212
|
| Signature.fromRpc.ErrorType
|
|
1247
1213
|
| Errors.GlobalErrorType
|
|
1248
1214
|
}
|
|
@@ -1317,12 +1283,7 @@ export function getType<
|
|
|
1317
1283
|
return 'keychain' as never
|
|
1318
1284
|
|
|
1319
1285
|
// Detect Multisig signature
|
|
1320
|
-
if (
|
|
1321
|
-
('account' in envelope ||
|
|
1322
|
-
'initialConfig' in envelope ||
|
|
1323
|
-
'init' in envelope) &&
|
|
1324
|
-
'signatures' in envelope
|
|
1325
|
-
)
|
|
1286
|
+
if ('config' in envelope && 'signatures' in envelope)
|
|
1326
1287
|
return 'multisig' as never
|
|
1327
1288
|
|
|
1328
1289
|
throw new CoercionError({
|
|
@@ -1339,7 +1300,7 @@ export function getType<
|
|
|
1339
1300
|
* - WebAuthn: `0x02` + webauthnData (variable) + r (32) + s (32) + pubKeyX (32) + pubKeyY (32)
|
|
1340
1301
|
* - Keychain V1: `0x03` + userAddress (20) + inner signature (recursive)
|
|
1341
1302
|
* - Keychain V2: `0x04` + userAddress (20) + inner signature (recursive)
|
|
1342
|
-
* - Multisig: `0x05` + RLP `[account
|
|
1303
|
+
* - Multisig: `0x05` + RLP `[account, config, signatures]`
|
|
1343
1304
|
*
|
|
1344
1305
|
* [Signature Types](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types)
|
|
1345
1306
|
*
|
|
@@ -1426,14 +1387,11 @@ export function serialize(
|
|
|
1426
1387
|
if (type === 'multisig') {
|
|
1427
1388
|
const multisig = envelope as Multisig
|
|
1428
1389
|
assert(multisig)
|
|
1429
|
-
// The first field is either the initialized account or the bootstrap init
|
|
1430
|
-
// config. Each owner approval is an encoded signature.
|
|
1431
1390
|
return Hex.concat(
|
|
1432
1391
|
serializedMultisigType,
|
|
1433
1392
|
Rlp.fromHex([
|
|
1434
|
-
multisig.
|
|
1435
|
-
|
|
1436
|
-
: multisig.account,
|
|
1393
|
+
multisig.account,
|
|
1394
|
+
MultisigConfig.toTuple(multisig.config),
|
|
1437
1395
|
multisig.signatures.map((signature) => serialize(signature)),
|
|
1438
1396
|
]),
|
|
1439
1397
|
options.magic ? magicBytes : '0x',
|
|
@@ -1474,9 +1432,6 @@ export declare namespace serialize {
|
|
|
1474
1432
|
* recovered owner address. Works for any owner key type (secp256k1, p256,
|
|
1475
1433
|
* webAuthn).
|
|
1476
1434
|
*
|
|
1477
|
-
* Config updates never change `account`, so the initial config is the correct
|
|
1478
|
-
* input even for post-update transactions.
|
|
1479
|
-
*
|
|
1480
1435
|
* @example
|
|
1481
1436
|
* ```ts twoslash
|
|
1482
1437
|
* import { Secp256k1 } from 'ox'
|
|
@@ -1486,8 +1441,7 @@ export declare namespace serialize {
|
|
|
1486
1441
|
* TxEnvelopeTempo
|
|
1487
1442
|
* } from 'ox/tempo'
|
|
1488
1443
|
*
|
|
1489
|
-
* const
|
|
1490
|
-
* threshold: 2,
|
|
1444
|
+
* const config = MultisigConfig.from({
|
|
1491
1445
|
* owners: [
|
|
1492
1446
|
* {
|
|
1493
1447
|
* owner: '0x1111111111111111111111111111111111111111',
|
|
@@ -1497,8 +1451,10 @@ export declare namespace serialize {
|
|
|
1497
1451
|
* owner: '0x2222222222222222222222222222222222222222',
|
|
1498
1452
|
* weight: 1
|
|
1499
1453
|
* }
|
|
1500
|
-
* ]
|
|
1454
|
+
* ],
|
|
1455
|
+
* threshold: 2
|
|
1501
1456
|
* })
|
|
1457
|
+
* const account = MultisigConfig.getAddress(config)
|
|
1502
1458
|
*
|
|
1503
1459
|
* const tx = TxEnvelopeTempo.from({ chainId: 1, calls: [] })
|
|
1504
1460
|
* const payload = TxEnvelopeTempo.getSignPayload(tx)
|
|
@@ -1508,8 +1464,9 @@ export declare namespace serialize {
|
|
|
1508
1464
|
* Secp256k1.randomPrivateKey()
|
|
1509
1465
|
* ]
|
|
1510
1466
|
* const digest = MultisigConfig.getSignPayload({
|
|
1511
|
-
*
|
|
1512
|
-
*
|
|
1467
|
+
* account,
|
|
1468
|
+
* config,
|
|
1469
|
+
* payload
|
|
1513
1470
|
* })
|
|
1514
1471
|
* const signatures = privateKeys.map((privateKey) =>
|
|
1515
1472
|
* SignatureEnvelope.from(
|
|
@@ -1519,7 +1476,8 @@ export declare namespace serialize {
|
|
|
1519
1476
|
*
|
|
1520
1477
|
* const ordered = SignatureEnvelope.sortMultisigApprovals({
|
|
1521
1478
|
* // [!code focus]
|
|
1522
|
-
*
|
|
1479
|
+
* account, // [!code focus]
|
|
1480
|
+
* config, // [!code focus]
|
|
1523
1481
|
* payload, // [!code focus]
|
|
1524
1482
|
* signatures // [!code focus]
|
|
1525
1483
|
* }) // [!code focus]
|
|
@@ -1531,16 +1489,12 @@ export declare namespace serialize {
|
|
|
1531
1489
|
export function sortMultisigApprovals(
|
|
1532
1490
|
value: sortMultisigApprovals.Value,
|
|
1533
1491
|
): readonly SignatureEnvelope[] {
|
|
1534
|
-
const {
|
|
1535
|
-
const digest = MultisigConfig.getSignPayload(
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
account: (value as { account: Address.Address }).account,
|
|
1541
|
-
version,
|
|
1542
|
-
},
|
|
1543
|
-
)
|
|
1492
|
+
const { account, config, payload, signatures } = value
|
|
1493
|
+
const digest = MultisigConfig.getSignPayload({
|
|
1494
|
+
account,
|
|
1495
|
+
config: MultisigConfig.from(config),
|
|
1496
|
+
payload,
|
|
1497
|
+
})
|
|
1544
1498
|
// Recover each signer once (decorate–sort–undecorate) rather than inside the
|
|
1545
1499
|
// comparator.
|
|
1546
1500
|
return signatures
|
|
@@ -1554,25 +1508,15 @@ export function sortMultisigApprovals(
|
|
|
1554
1508
|
|
|
1555
1509
|
export declare namespace sortMultisigApprovals {
|
|
1556
1510
|
type Value = {
|
|
1511
|
+
/** The native multisig account address. */
|
|
1512
|
+
account: Address.Address
|
|
1513
|
+
/** Complete applicable multisig configuration witness. */
|
|
1514
|
+
config: MultisigConfig.Input
|
|
1557
1515
|
/** The inner transaction sign payload (`tx.signature_hash()`). */
|
|
1558
1516
|
payload: Hex.Hex | Bytes.Bytes
|
|
1559
1517
|
/** The owner approvals to order. */
|
|
1560
1518
|
signatures: readonly SignatureEnvelope[]
|
|
1561
|
-
|
|
1562
|
-
version?: bigint | undefined
|
|
1563
|
-
} & OneOf<
|
|
1564
|
-
| {
|
|
1565
|
-
/** The native multisig account address. */
|
|
1566
|
-
account: Address.Address
|
|
1567
|
-
}
|
|
1568
|
-
| {
|
|
1569
|
-
/**
|
|
1570
|
-
* The initial multisig config (the bootstrap config that derived the
|
|
1571
|
-
* permanent `account`). Used to derive the account automatically.
|
|
1572
|
-
*/
|
|
1573
|
-
initialConfig: MultisigConfig.Config
|
|
1574
|
-
}
|
|
1575
|
-
>
|
|
1519
|
+
}
|
|
1576
1520
|
|
|
1577
1521
|
type ErrorType =
|
|
1578
1522
|
| MultisigConfig.getSignPayload.ErrorType
|
|
@@ -1656,25 +1600,10 @@ export function toRpc<const envelope extends toRpc.Input>(
|
|
|
1656
1600
|
if (type === 'multisig') {
|
|
1657
1601
|
const multisig = envelope as Multisig
|
|
1658
1602
|
assert(multisig)
|
|
1659
|
-
const signatures = multisig.signatures.map((signature) => toRpc(signature))
|
|
1660
|
-
if (multisig.init) {
|
|
1661
|
-
const init = {
|
|
1662
|
-
...multisig.init,
|
|
1663
|
-
salt: multisig.init.salt ?? MultisigConfig.zeroSalt,
|
|
1664
|
-
threshold: Number(multisig.init.threshold),
|
|
1665
|
-
owners: multisig.init.owners.map((owner) => ({
|
|
1666
|
-
...owner,
|
|
1667
|
-
weight: Number(owner.weight),
|
|
1668
|
-
})),
|
|
1669
|
-
}
|
|
1670
|
-
return {
|
|
1671
|
-
init,
|
|
1672
|
-
signatures,
|
|
1673
|
-
} as never
|
|
1674
|
-
}
|
|
1675
1603
|
return {
|
|
1676
1604
|
account: multisig.account,
|
|
1677
|
-
|
|
1605
|
+
config: MultisigConfig.toRpc(multisig.config),
|
|
1606
|
+
signatures: multisig.signatures.map((signature) => toRpc(signature)),
|
|
1678
1607
|
} as never
|
|
1679
1608
|
}
|
|
1680
1609
|
|
|
@@ -1702,6 +1631,7 @@ export declare namespace toRpc {
|
|
|
1702
1631
|
type ErrorType =
|
|
1703
1632
|
| assert.ErrorType
|
|
1704
1633
|
| CoercionError
|
|
1634
|
+
| MultisigConfig.toRpc.ErrorType
|
|
1705
1635
|
| Signature.toRpc.ErrorType
|
|
1706
1636
|
| Errors.GlobalErrorType
|
|
1707
1637
|
}
|