ox 0.14.55 → 0.14.57
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 +48 -0
- package/_cjs/tempo/{MultisigConfig.js → AccountConfig.js} +32 -9
- package/_cjs/tempo/AccountConfig.js.map +1 -0
- package/_cjs/tempo/{MultisigOperation.js → AccountOperation.js} +29 -29
- package/_cjs/tempo/AccountOperation.js.map +1 -0
- package/_cjs/tempo/{MultisigSimulation.js → AccountSimulation.js} +22 -13
- package/_cjs/tempo/AccountSimulation.js.map +1 -0
- package/_cjs/tempo/KeyAuthorization.js +10 -18
- package/_cjs/tempo/KeyAuthorization.js.map +1 -1
- package/_cjs/tempo/SignatureEnvelope.js +64 -64
- package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
- package/_cjs/tempo/TransactionRequest.js +15 -10
- package/_cjs/tempo/TransactionRequest.js.map +1 -1
- package/_cjs/tempo/index.js +4 -4
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/tempo/{MultisigConfig.js → AccountConfig.js} +161 -64
- package/_esm/tempo/AccountConfig.js.map +1 -0
- package/_esm/tempo/{MultisigOperation.js → AccountOperation.js} +64 -64
- package/_esm/tempo/AccountOperation.js.map +1 -0
- package/_esm/tempo/{MultisigSimulation.js → AccountSimulation.js} +35 -25
- package/_esm/tempo/AccountSimulation.js.map +1 -0
- package/_esm/tempo/KeyAuthorization.js +16 -19
- package/_esm/tempo/KeyAuthorization.js.map +1 -1
- package/_esm/tempo/SignatureEnvelope.js +71 -71
- package/_esm/tempo/SignatureEnvelope.js.map +1 -1
- package/_esm/tempo/TransactionRequest.js +15 -10
- package/_esm/tempo/TransactionRequest.js.map +1 -1
- package/_esm/tempo/index.js +50 -48
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/tempo/{MultisigConfig.d.ts → AccountConfig.d.ts} +156 -66
- package/_types/tempo/AccountConfig.d.ts.map +1 -0
- package/_types/tempo/{MultisigOperation.d.ts → AccountOperation.d.ts} +62 -62
- package/_types/tempo/AccountOperation.d.ts.map +1 -0
- package/_types/tempo/{MultisigSimulation.d.ts → AccountSimulation.d.ts} +25 -21
- package/_types/tempo/AccountSimulation.d.ts.map +1 -0
- package/_types/tempo/KeyAuthorization.d.ts +28 -23
- package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
- package/_types/tempo/RpcSchemaTempo.d.ts +13 -13
- package/_types/tempo/RpcSchemaTempo.d.ts.map +1 -1
- package/_types/tempo/SignatureEnvelope.d.ts +36 -33
- package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
- package/_types/tempo/TransactionRequest.d.ts +11 -9
- package/_types/tempo/TransactionRequest.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +50 -48
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/package.json +31 -31
- package/tempo/AccountConfig/package.json +6 -0
- package/tempo/AccountConfig.test-d/package.json +6 -0
- package/tempo/AccountConfig.test-d.ts +72 -0
- package/tempo/AccountConfig.test.ts +642 -0
- package/tempo/{MultisigConfig.ts → AccountConfig.ts} +212 -75
- package/tempo/AccountOperation/package.json +6 -0
- package/tempo/AccountOperation.test-d/package.json +6 -0
- package/tempo/AccountOperation.test-d.ts +71 -0
- package/tempo/{MultisigOperation.test.ts → AccountOperation.test.ts} +129 -129
- package/tempo/{MultisigOperation.ts → AccountOperation.ts} +95 -97
- package/tempo/AccountSimulation/package.json +6 -0
- package/tempo/AccountSimulation.test-d/package.json +6 -0
- package/tempo/{MultisigSimulation.test-d.ts → AccountSimulation.test-d.ts} +7 -9
- package/tempo/{MultisigSimulation.test.ts → AccountSimulation.test.ts} +73 -29
- package/tempo/{MultisigSimulation.ts → AccountSimulation.ts} +47 -35
- package/tempo/KeyAuthorization.test-d.ts +19 -29
- package/tempo/KeyAuthorization.test.ts +151 -74
- package/tempo/KeyAuthorization.ts +40 -61
- package/tempo/RpcSchemaTempo.test-d.ts +20 -20
- package/tempo/RpcSchemaTempo.ts +13 -13
- package/tempo/SignatureEnvelope.test-d.ts +7 -7
- package/tempo/SignatureEnvelope.test.ts +34 -34
- package/tempo/SignatureEnvelope.ts +107 -103
- package/tempo/Transaction.test.ts +4 -4
- package/tempo/TransactionRequest.test-d.ts +17 -8
- package/tempo/TransactionRequest.test.ts +31 -21
- package/tempo/TransactionRequest.ts +29 -20
- package/tempo/{multisig.e2e.test.ts → configurableAccounts.e2e.test.ts} +16 -16
- package/tempo/index.ts +50 -48
- package/version.ts +1 -1
- package/_cjs/tempo/MultisigConfig.js.map +0 -1
- package/_cjs/tempo/MultisigOperation.js.map +0 -1
- package/_cjs/tempo/MultisigSimulation.js.map +0 -1
- package/_esm/tempo/MultisigConfig.js.map +0 -1
- package/_esm/tempo/MultisigOperation.js.map +0 -1
- package/_esm/tempo/MultisigSimulation.js.map +0 -1
- package/_types/tempo/MultisigConfig.d.ts.map +0 -1
- package/_types/tempo/MultisigOperation.d.ts.map +0 -1
- package/_types/tempo/MultisigSimulation.d.ts.map +0 -1
- package/tempo/MultisigConfig/package.json +0 -6
- package/tempo/MultisigConfig.test-d/package.json +0 -6
- package/tempo/MultisigConfig.test-d.ts +0 -52
- package/tempo/MultisigConfig.test.ts +0 -391
- package/tempo/MultisigOperation/package.json +0 -6
- package/tempo/MultisigOperation.test-d/package.json +0 -6
- package/tempo/MultisigOperation.test-d.ts +0 -71
- package/tempo/MultisigSimulation/package.json +0 -6
- package/tempo/MultisigSimulation.test-d/package.json +0 -6
|
@@ -18,14 +18,14 @@ import * as ox_Secp256k1 from '../core/Secp256k1.js'
|
|
|
18
18
|
import * as Signature from '../core/Signature.js'
|
|
19
19
|
import type * as WebAuthnP256 from '../core/WebAuthnP256.js'
|
|
20
20
|
import * as ox_WebAuthnP256 from '../core/WebAuthnP256.js'
|
|
21
|
-
import * as
|
|
21
|
+
import * as AccountConfig from './AccountConfig.js'
|
|
22
22
|
|
|
23
23
|
/** Signature type identifiers for encoding/decoding */
|
|
24
24
|
const serializedP256Type = '0x01'
|
|
25
25
|
const serializedWebAuthnType = '0x02'
|
|
26
26
|
const serializedKeychainType = '0x03'
|
|
27
27
|
const serializedKeychainV2Type = '0x04'
|
|
28
|
-
const
|
|
28
|
+
const serializedConfigurableType = '0x05'
|
|
29
29
|
|
|
30
30
|
type EnvelopeOneOf<
|
|
31
31
|
union extends object,
|
|
@@ -115,10 +115,10 @@ export type GetType<
|
|
|
115
115
|
? 'keychain'
|
|
116
116
|
: envelope extends {
|
|
117
117
|
account: Address.Address
|
|
118
|
-
config:
|
|
118
|
+
config: AccountConfig.Input
|
|
119
119
|
signatures: any
|
|
120
120
|
}
|
|
121
|
-
? '
|
|
121
|
+
? 'configurable'
|
|
122
122
|
: never
|
|
123
123
|
|
|
124
124
|
/**
|
|
@@ -142,6 +142,9 @@ export type GetType<
|
|
|
142
142
|
* V2 binds the signature to the user account via `keccak256(sigHash || userAddress)`.
|
|
143
143
|
* The protocol validates the access key authorization via the AccountKeychain precompile.
|
|
144
144
|
*
|
|
145
|
+
* - **configurable** (type `0x05`): Configurable account signature carrying the account address,
|
|
146
|
+
* its complete current configuration, and primitive owner approvals over the version-bound digest.
|
|
147
|
+
*
|
|
145
148
|
* [Signature Types Specification](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types)
|
|
146
149
|
*/
|
|
147
150
|
export type SignatureEnvelope<bigintType = bigint, numberType = number> =
|
|
@@ -152,7 +155,7 @@ export type SignatureEnvelope<bigintType = bigint, numberType = number> =
|
|
|
152
155
|
| Keychain<bigintType, numberType>,
|
|
153
156
|
SignatureEnvelopeKey
|
|
154
157
|
>
|
|
155
|
-
| EnvelopeOneOf<
|
|
158
|
+
| EnvelopeOneOf<Configurable<bigintType, numberType>, SignatureEnvelopeKey>
|
|
156
159
|
|
|
157
160
|
/**
|
|
158
161
|
* RPC-formatted signature envelope.
|
|
@@ -162,7 +165,7 @@ export type SignatureEnvelopeRpc =
|
|
|
162
165
|
Secp256k1Rpc | P256Rpc | WebAuthnRpc | KeychainRpc,
|
|
163
166
|
SignatureEnvelopeRpcKey
|
|
164
167
|
>
|
|
165
|
-
|
|
|
168
|
+
| ConfigurableRpc
|
|
166
169
|
|
|
167
170
|
/** Primitive signature envelope accepted by protocol sidecars. */
|
|
168
171
|
export type Primitive<bigintType = bigint, numberType = number> = OneOf<
|
|
@@ -204,24 +207,24 @@ export type KeychainRpc = {
|
|
|
204
207
|
}
|
|
205
208
|
|
|
206
209
|
/**
|
|
207
|
-
*
|
|
210
|
+
* Configurable account signature (type `0x05`).
|
|
208
211
|
*
|
|
209
212
|
* Carries the account's complete current configuration and primitive owner
|
|
210
213
|
* approvals over its version-bound digest. The node validates the account
|
|
211
214
|
* identity or stored commitment and the owner quorum against chain state.
|
|
212
215
|
*/
|
|
213
|
-
export type
|
|
214
|
-
/** Permanent
|
|
216
|
+
export type Configurable<bigintType = bigint, numberType = number> = {
|
|
217
|
+
/** Permanent account address. */
|
|
215
218
|
account: Address.Address
|
|
216
219
|
/** Complete current configuration, included in every signature. */
|
|
217
|
-
config:
|
|
220
|
+
config: AccountConfig.Config<bigintType, numberType>
|
|
218
221
|
/** Primitive owner approvals in ascending recovered-address order. */
|
|
219
222
|
signatures: readonly Primitive<bigintType, numberType>[]
|
|
220
|
-
type: '
|
|
223
|
+
type: 'configurable'
|
|
221
224
|
}
|
|
222
225
|
|
|
223
226
|
/** RLP-encoded `[account, config, signatures]`, without the `0x05` type byte. */
|
|
224
|
-
export type
|
|
227
|
+
export type ConfigurableRpc = Hex.Hex
|
|
225
228
|
|
|
226
229
|
export type P256<bigintType = bigint, numberType = number> = {
|
|
227
230
|
prehash: boolean
|
|
@@ -364,9 +367,9 @@ export function assert(envelope: PartialBy<SignatureEnvelope, 'type'>): void {
|
|
|
364
367
|
return
|
|
365
368
|
}
|
|
366
369
|
|
|
367
|
-
if (type === '
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
+
if (type === 'configurable') {
|
|
371
|
+
const configurable = envelope as Configurable
|
|
372
|
+
assertConfigurable(configurable)
|
|
370
373
|
return
|
|
371
374
|
}
|
|
372
375
|
}
|
|
@@ -374,10 +377,10 @@ export function assert(envelope: PartialBy<SignatureEnvelope, 'type'>): void {
|
|
|
374
377
|
export declare namespace assert {
|
|
375
378
|
type ErrorType =
|
|
376
379
|
| CoercionError
|
|
377
|
-
|
|
|
380
|
+
| InvalidApprovalError
|
|
378
381
|
| MissingPropertiesError
|
|
379
|
-
|
|
|
380
|
-
|
|
|
382
|
+
| AccountConfig.assert.ErrorType
|
|
383
|
+
| AccountConfig.getAddress.ErrorType
|
|
381
384
|
| Signature.assert.ErrorType
|
|
382
385
|
| Errors.GlobalErrorType
|
|
383
386
|
}
|
|
@@ -386,13 +389,13 @@ function assertKeychainVersion(keychain: Keychain): void {
|
|
|
386
389
|
if (keychain.version !== 'v1') return
|
|
387
390
|
let inner = keychain.inner
|
|
388
391
|
while (getType(inner) === 'keychain') inner = (inner as Keychain).inner
|
|
389
|
-
if (getType(inner) === '
|
|
390
|
-
throw new
|
|
391
|
-
reason: '
|
|
392
|
+
if (getType(inner) === 'configurable')
|
|
393
|
+
throw new InvalidApprovalError({
|
|
394
|
+
reason: 'configurable access keys require keychain V2',
|
|
392
395
|
})
|
|
393
396
|
}
|
|
394
397
|
|
|
395
|
-
function
|
|
398
|
+
function assertConfigurable(envelope: Configurable): void {
|
|
396
399
|
const missing: string[] = []
|
|
397
400
|
if (!envelope.account) missing.push('account')
|
|
398
401
|
if (!envelope.config) missing.push('config')
|
|
@@ -401,47 +404,47 @@ function assertMultisig(envelope: Multisig): void {
|
|
|
401
404
|
throw new MissingPropertiesError({
|
|
402
405
|
envelope,
|
|
403
406
|
missing,
|
|
404
|
-
type: '
|
|
407
|
+
type: 'configurable',
|
|
405
408
|
})
|
|
406
409
|
if (!Address.validate(envelope.account))
|
|
407
|
-
throw new
|
|
408
|
-
reason: '
|
|
410
|
+
throw new InvalidApprovalError({
|
|
411
|
+
reason: 'configurable account is invalid',
|
|
409
412
|
})
|
|
410
413
|
if (Hex.toBigInt(envelope.account) === 0n)
|
|
411
|
-
throw new
|
|
412
|
-
reason: '
|
|
414
|
+
throw new InvalidApprovalError({
|
|
415
|
+
reason: 'configurable account cannot be zero',
|
|
413
416
|
})
|
|
414
417
|
if (envelope.signatures.length === 0)
|
|
415
|
-
throw new
|
|
416
|
-
reason: '
|
|
418
|
+
throw new InvalidApprovalError({
|
|
419
|
+
reason: 'configurable signatures cannot be empty',
|
|
417
420
|
})
|
|
418
|
-
if (envelope.signatures.length >
|
|
419
|
-
throw new
|
|
420
|
-
reason: `
|
|
421
|
+
if (envelope.signatures.length > AccountConfig.maxSignatures)
|
|
422
|
+
throw new InvalidApprovalError({
|
|
423
|
+
reason: `configurable signatures exceed ${AccountConfig.maxSignatures}`,
|
|
421
424
|
})
|
|
422
425
|
|
|
423
|
-
|
|
426
|
+
AccountConfig.assert(envelope.config)
|
|
424
427
|
if (
|
|
425
428
|
(envelope.config.version ?? 0n) === 0n &&
|
|
426
429
|
envelope.config.owners.some((owner) =>
|
|
427
430
|
Address.isEqual(owner.owner, envelope.account),
|
|
428
431
|
)
|
|
429
432
|
)
|
|
430
|
-
throw new
|
|
433
|
+
throw new InvalidApprovalError({
|
|
431
434
|
reason: 'initial account cannot be an owner',
|
|
432
435
|
})
|
|
433
436
|
|
|
434
437
|
for (const inner of envelope.signatures) {
|
|
435
438
|
const type = getType(inner as SignatureEnvelope)
|
|
436
|
-
if (type === 'keychain' || type === '
|
|
437
|
-
throw new
|
|
439
|
+
if (type === 'keychain' || type === 'configurable')
|
|
440
|
+
throw new InvalidApprovalError({
|
|
438
441
|
reason: 'owner approvals must be primitive signatures',
|
|
439
442
|
})
|
|
440
443
|
assert(inner)
|
|
441
444
|
|
|
442
|
-
if (Hex.size(serialize(inner)) >
|
|
443
|
-
throw new
|
|
444
|
-
reason: `
|
|
445
|
+
if (Hex.size(serialize(inner)) > AccountConfig.maxOwnerSignatureBytes)
|
|
446
|
+
throw new InvalidApprovalError({
|
|
447
|
+
reason: `configurable owner signature exceeds ${AccountConfig.maxOwnerSignatureBytes} bytes`,
|
|
445
448
|
})
|
|
446
449
|
}
|
|
447
450
|
}
|
|
@@ -479,9 +482,9 @@ export function extractAddress(
|
|
|
479
482
|
if (root) return signature.userAddress
|
|
480
483
|
return extractAddress({ ...options, signature: signature.inner })
|
|
481
484
|
}
|
|
482
|
-
//
|
|
483
|
-
// derived
|
|
484
|
-
if (signature.type === '
|
|
485
|
+
// Configurable signatures have no single signer; the recovered sender is the
|
|
486
|
+
// derived configurable account address.
|
|
487
|
+
if (signature.type === 'configurable') return signature.account
|
|
485
488
|
return Address.fromPublicKey(extractPublicKey(options))
|
|
486
489
|
}
|
|
487
490
|
|
|
@@ -544,9 +547,9 @@ export function extractPublicKey(
|
|
|
544
547
|
return signature.publicKey
|
|
545
548
|
case 'keychain':
|
|
546
549
|
return extractPublicKey({ payload, signature: signature.inner })
|
|
547
|
-
case '
|
|
548
|
-
// A
|
|
549
|
-
// single public key; recover the
|
|
550
|
+
case 'configurable':
|
|
551
|
+
// A configurable signature aggregates multiple owner approvals and has no
|
|
552
|
+
// single public key; recover the configurable account via `extractAddress`.
|
|
550
553
|
throw new CoercionError({ envelope: signature })
|
|
551
554
|
}
|
|
552
555
|
}
|
|
@@ -717,46 +720,45 @@ function deserialize_(value: Serialized): SignatureEnvelope {
|
|
|
717
720
|
return envelope
|
|
718
721
|
}
|
|
719
722
|
|
|
720
|
-
if (typeId ===
|
|
723
|
+
if (typeId === serializedConfigurableType) {
|
|
721
724
|
const decoded = Rlp.toHex(data)
|
|
722
725
|
if (!Array.isArray(decoded) || decoded.length !== 3)
|
|
723
726
|
throw new InvalidSerializedError({
|
|
724
|
-
reason:
|
|
727
|
+
reason:
|
|
728
|
+
'invalid configurable wire shape: expected exactly three fields',
|
|
725
729
|
serialized,
|
|
726
730
|
})
|
|
727
731
|
const [account, config, signatures] = decoded
|
|
728
732
|
if (typeof account !== 'string' || !Address.validate(account))
|
|
729
733
|
throw new InvalidSerializedError({
|
|
730
|
-
reason: 'invalid
|
|
734
|
+
reason: 'invalid configurable account',
|
|
731
735
|
serialized,
|
|
732
736
|
})
|
|
733
737
|
if (!Array.isArray(config))
|
|
734
738
|
throw new InvalidSerializedError({
|
|
735
|
-
reason: 'invalid
|
|
739
|
+
reason: 'invalid account config',
|
|
736
740
|
serialized,
|
|
737
741
|
})
|
|
738
742
|
if (
|
|
739
743
|
!Array.isArray(signatures) ||
|
|
740
744
|
signatures.length === 0 ||
|
|
741
|
-
signatures.length >
|
|
745
|
+
signatures.length > AccountConfig.maxSignatures
|
|
742
746
|
)
|
|
743
747
|
throw new InvalidSerializedError({
|
|
744
|
-
reason: 'invalid
|
|
748
|
+
reason: 'invalid configurable signatures list',
|
|
745
749
|
serialized,
|
|
746
750
|
})
|
|
747
751
|
const envelope = {
|
|
748
|
-
type: '
|
|
752
|
+
type: 'configurable',
|
|
749
753
|
account,
|
|
750
|
-
config:
|
|
751
|
-
config as unknown as MultisigConfig.Tuple,
|
|
752
|
-
),
|
|
754
|
+
config: AccountConfig.fromTuple(config as unknown as AccountConfig.Tuple),
|
|
753
755
|
signatures: signatures.map((signature) => {
|
|
754
756
|
if (
|
|
755
757
|
!Hex.validate(signature) ||
|
|
756
|
-
Hex.size(signature) >
|
|
758
|
+
Hex.size(signature) > AccountConfig.maxOwnerSignatureBytes
|
|
757
759
|
)
|
|
758
760
|
throw new InvalidSerializedError({
|
|
759
|
-
reason: 'invalid
|
|
761
|
+
reason: 'invalid configurable owner signature',
|
|
760
762
|
serialized,
|
|
761
763
|
})
|
|
762
764
|
// Reject recursive envelopes before decoding their contents.
|
|
@@ -770,13 +772,13 @@ function deserialize_(value: Serialized): SignatureEnvelope {
|
|
|
770
772
|
})
|
|
771
773
|
return deserialize(signature) as Primitive
|
|
772
774
|
}),
|
|
773
|
-
} satisfies
|
|
774
|
-
|
|
775
|
+
} satisfies Configurable
|
|
776
|
+
assertConfigurable(envelope)
|
|
775
777
|
return envelope
|
|
776
778
|
}
|
|
777
779
|
|
|
778
780
|
throw new InvalidSerializedError({
|
|
779
|
-
reason: `Unknown signature type identifier: ${typeId}. Expected ${serializedP256Type} (P256), ${serializedWebAuthnType} (WebAuthn), ${serializedKeychainType} (Keychain V1), ${serializedKeychainV2Type} (Keychain V2), or ${
|
|
781
|
+
reason: `Unknown signature type identifier: ${typeId}. Expected ${serializedP256Type} (P256), ${serializedWebAuthnType} (WebAuthn), ${serializedKeychainType} (Keychain V1), ${serializedKeychainV2Type} (Keychain V2), or ${serializedConfigurableType} (Configurable)`,
|
|
780
782
|
serialized,
|
|
781
783
|
})
|
|
782
784
|
}
|
|
@@ -894,7 +896,7 @@ function deserialize_(value: Serialized): SignatureEnvelope {
|
|
|
894
896
|
* ```
|
|
895
897
|
*
|
|
896
898
|
* @example
|
|
897
|
-
* ###
|
|
899
|
+
* ### Configurable
|
|
898
900
|
*
|
|
899
901
|
* Include the permanent account and current configuration on every transaction.
|
|
900
902
|
*
|
|
@@ -943,12 +945,12 @@ export function from<const value extends from.Value>(
|
|
|
943
945
|
|
|
944
946
|
const type = getType(value)
|
|
945
947
|
|
|
946
|
-
if (type === '
|
|
947
|
-
const
|
|
948
|
+
if (type === 'configurable') {
|
|
949
|
+
const configurable = value as Configurable
|
|
948
950
|
return {
|
|
949
|
-
...
|
|
950
|
-
config:
|
|
951
|
-
signatures:
|
|
951
|
+
...configurable,
|
|
952
|
+
config: AccountConfig.from(configurable.config),
|
|
953
|
+
signatures: configurable.signatures.map((signature) => from(signature)),
|
|
952
954
|
type,
|
|
953
955
|
} as never
|
|
954
956
|
}
|
|
@@ -995,14 +997,14 @@ export declare namespace from {
|
|
|
995
997
|
payload?: Hex.Hex | Bytes.Bytes | undefined
|
|
996
998
|
}
|
|
997
999
|
|
|
998
|
-
/**
|
|
999
|
-
type
|
|
1000
|
-
config:
|
|
1001
|
-
type?: '
|
|
1000
|
+
/** Configurable input with an explicit account and a normalizable configuration. */
|
|
1001
|
+
type ConfigurableFromConfig = Omit<Configurable, 'config' | 'type'> & {
|
|
1002
|
+
config: AccountConfig.Input
|
|
1003
|
+
type?: 'configurable' | undefined
|
|
1002
1004
|
}
|
|
1003
1005
|
|
|
1004
1006
|
type Value =
|
|
1005
|
-
|
|
|
1007
|
+
| ConfigurableFromConfig
|
|
1006
1008
|
| UnionPartialBy<SignatureEnvelope, 'prehash' | 'type'>
|
|
1007
1009
|
| Secp256k1Flat
|
|
1008
1010
|
| Serialized
|
|
@@ -1011,8 +1013,8 @@ export declare namespace from {
|
|
|
1011
1013
|
? SignatureEnvelope
|
|
1012
1014
|
: value extends Secp256k1Flat
|
|
1013
1015
|
? Secp256k1
|
|
1014
|
-
: value extends
|
|
1015
|
-
? Extract<SignatureEnvelope, { type: '
|
|
1016
|
+
: value extends ConfigurableFromConfig
|
|
1017
|
+
? Extract<SignatureEnvelope, { type: 'configurable' }>
|
|
1016
1018
|
: IsNarrowable<value, SignatureEnvelope> extends true
|
|
1017
1019
|
? SignatureEnvelope
|
|
1018
1020
|
: Assign<
|
|
@@ -1045,8 +1047,10 @@ export declare namespace from {
|
|
|
1045
1047
|
*/
|
|
1046
1048
|
export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
|
|
1047
1049
|
if (typeof envelope === 'string') {
|
|
1048
|
-
const signature = deserialize(
|
|
1049
|
-
|
|
1050
|
+
const signature = deserialize(
|
|
1051
|
+
Hex.concat(serializedConfigurableType, envelope),
|
|
1052
|
+
)
|
|
1053
|
+
if (signature.type !== 'configurable') throw new CoercionError({ envelope })
|
|
1050
1054
|
return signature
|
|
1051
1055
|
}
|
|
1052
1056
|
if (envelope.type === 'secp256k1')
|
|
@@ -1141,7 +1145,7 @@ export declare namespace fromRpc {
|
|
|
1141
1145
|
| assert.ErrorType
|
|
1142
1146
|
| CoercionError
|
|
1143
1147
|
| InvalidSerializedError
|
|
1144
|
-
|
|
|
1148
|
+
| AccountConfig.getAddress.ErrorType
|
|
1145
1149
|
| Signature.fromRpc.ErrorType
|
|
1146
1150
|
| Errors.GlobalErrorType
|
|
1147
1151
|
}
|
|
@@ -1211,9 +1215,9 @@ export function getType<
|
|
|
1211
1215
|
if ('userAddress' in envelope && 'inner' in envelope)
|
|
1212
1216
|
return 'keychain' as never
|
|
1213
1217
|
|
|
1214
|
-
// Detect
|
|
1218
|
+
// Detect Configurable signature
|
|
1215
1219
|
if ('account' in envelope && 'config' in envelope && 'signatures' in envelope)
|
|
1216
|
-
return '
|
|
1220
|
+
return 'configurable' as never
|
|
1217
1221
|
|
|
1218
1222
|
throw new CoercionError({
|
|
1219
1223
|
envelope,
|
|
@@ -1229,7 +1233,7 @@ export function getType<
|
|
|
1229
1233
|
* - WebAuthn: `0x02` + webauthnData (variable) + r (32) + s (32) + pubKeyX (32) + pubKeyY (32)
|
|
1230
1234
|
* - Keychain V1: `0x03` + userAddress (20) + inner signature (recursive)
|
|
1231
1235
|
* - Keychain V2: `0x04` + userAddress (20) + inner signature (recursive)
|
|
1232
|
-
* -
|
|
1236
|
+
* - Configurable: `0x05` + RLP `[account, config, signatures]`
|
|
1233
1237
|
*
|
|
1234
1238
|
* [Signature Types](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#signature-types)
|
|
1235
1239
|
*
|
|
@@ -1310,15 +1314,15 @@ export function serialize(
|
|
|
1310
1314
|
)
|
|
1311
1315
|
}
|
|
1312
1316
|
|
|
1313
|
-
if (type === '
|
|
1314
|
-
const
|
|
1315
|
-
assert(
|
|
1317
|
+
if (type === 'configurable') {
|
|
1318
|
+
const configurable = envelope as Configurable
|
|
1319
|
+
assert(configurable)
|
|
1316
1320
|
return Hex.concat(
|
|
1317
|
-
|
|
1321
|
+
serializedConfigurableType,
|
|
1318
1322
|
Rlp.fromHex([
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1323
|
+
configurable.account,
|
|
1324
|
+
AccountConfig.toTuple(configurable.config),
|
|
1325
|
+
configurable.signatures.map((signature) => serialize(signature)),
|
|
1322
1326
|
]),
|
|
1323
1327
|
options.magic ? magicBytes : '0x',
|
|
1324
1328
|
)
|
|
@@ -1350,14 +1354,14 @@ export declare namespace serialize {
|
|
|
1350
1354
|
/**
|
|
1351
1355
|
* Sorts primitive owner approvals by recovered address.
|
|
1352
1356
|
*
|
|
1353
|
-
* Recovery uses the account and current config version's
|
|
1357
|
+
* Recovery uses the account and current config version's owner approval digest.
|
|
1354
1358
|
* Duplicate or non-owner approvals must still be rejected by the node.
|
|
1355
1359
|
*
|
|
1356
1360
|
* @example
|
|
1357
1361
|
* ```ts twoslash
|
|
1358
1362
|
* import { SignatureEnvelope } from 'ox/tempo'
|
|
1359
1363
|
*
|
|
1360
|
-
* const ordered = SignatureEnvelope.
|
|
1364
|
+
* const ordered = SignatureEnvelope.sortApprovals({
|
|
1361
1365
|
* account: '0x2222222222222222222222222222222222222222',
|
|
1362
1366
|
* config: { version: 0n },
|
|
1363
1367
|
* payload: `0x${'ab'.repeat(32)}`,
|
|
@@ -1368,11 +1372,11 @@ export declare namespace serialize {
|
|
|
1368
1372
|
* @param value - Account, version, payload, and primitive approvals.
|
|
1369
1373
|
* @returns The approvals in ascending recovered-address order.
|
|
1370
1374
|
*/
|
|
1371
|
-
export function
|
|
1372
|
-
value:
|
|
1375
|
+
export function sortApprovals(
|
|
1376
|
+
value: sortApprovals.Value,
|
|
1373
1377
|
): readonly Primitive[] {
|
|
1374
1378
|
const { signatures } = value
|
|
1375
|
-
const digest =
|
|
1379
|
+
const digest = AccountConfig.getSignPayload(value)
|
|
1376
1380
|
// Recover each signer once (decorate–sort–undecorate) rather than inside the
|
|
1377
1381
|
// comparator.
|
|
1378
1382
|
return signatures
|
|
@@ -1384,14 +1388,14 @@ export function sortMultisigApprovals(
|
|
|
1384
1388
|
.map((entry) => entry.signature)
|
|
1385
1389
|
}
|
|
1386
1390
|
|
|
1387
|
-
export declare namespace
|
|
1388
|
-
type Value =
|
|
1391
|
+
export declare namespace sortApprovals {
|
|
1392
|
+
type Value = AccountConfig.getSignPayload.Value & {
|
|
1389
1393
|
/** Primitive owner approvals to order. */
|
|
1390
1394
|
signatures: readonly Primitive[]
|
|
1391
1395
|
}
|
|
1392
1396
|
|
|
1393
1397
|
type ErrorType =
|
|
1394
|
-
|
|
|
1398
|
+
| AccountConfig.getSignPayload.ErrorType
|
|
1395
1399
|
| extractAddress.ErrorType
|
|
1396
1400
|
| Errors.GlobalErrorType
|
|
1397
1401
|
}
|
|
@@ -1466,8 +1470,8 @@ export function toRpc<const envelope extends toRpc.Input>(
|
|
|
1466
1470
|
} as never
|
|
1467
1471
|
}
|
|
1468
1472
|
|
|
1469
|
-
if (type === '
|
|
1470
|
-
return Hex.slice(serialize(envelope as
|
|
1473
|
+
if (type === 'configurable')
|
|
1474
|
+
return Hex.slice(serialize(envelope as Configurable), 1) as never
|
|
1471
1475
|
|
|
1472
1476
|
throw new CoercionError({ envelope })
|
|
1473
1477
|
}
|
|
@@ -1486,8 +1490,8 @@ export declare namespace toRpc {
|
|
|
1486
1490
|
? WebAuthnRpc
|
|
1487
1491
|
: GetType<envelope> extends 'keychain'
|
|
1488
1492
|
? KeychainRpc
|
|
1489
|
-
: GetType<envelope> extends '
|
|
1490
|
-
?
|
|
1493
|
+
: GetType<envelope> extends 'configurable'
|
|
1494
|
+
? ConfigurableRpc
|
|
1491
1495
|
: SignatureEnvelopeRpc
|
|
1492
1496
|
|
|
1493
1497
|
type ErrorType =
|
|
@@ -1727,7 +1731,7 @@ export class MissingPropertiesError extends Errors.BaseError {
|
|
|
1727
1731
|
}: {
|
|
1728
1732
|
envelope: unknown
|
|
1729
1733
|
missing: string[]
|
|
1730
|
-
type: Type | 'keychain' | '
|
|
1734
|
+
type: Type | 'keychain' | 'configurable'
|
|
1731
1735
|
}) {
|
|
1732
1736
|
super(
|
|
1733
1737
|
`Signature envelope of type "${type}" is missing required properties: ${missing.map((m) => `\`${m}\``).join(', ')}.\n\nProvided: ${Json.stringify(envelope)}`,
|
|
@@ -1754,12 +1758,12 @@ export class InvalidSerializedError extends Errors.BaseError {
|
|
|
1754
1758
|
}
|
|
1755
1759
|
|
|
1756
1760
|
/**
|
|
1757
|
-
* Error thrown when a
|
|
1761
|
+
* Error thrown when a configurable account owner approval is invalid.
|
|
1758
1762
|
*/
|
|
1759
|
-
export class
|
|
1760
|
-
override readonly name = 'SignatureEnvelope.
|
|
1763
|
+
export class InvalidApprovalError extends Errors.BaseError {
|
|
1764
|
+
override readonly name = 'SignatureEnvelope.InvalidApprovalError'
|
|
1761
1765
|
constructor({ reason }: { reason: string }) {
|
|
1762
|
-
super(`Invalid
|
|
1766
|
+
super(`Invalid owner approval: ${reason}.`)
|
|
1763
1767
|
}
|
|
1764
1768
|
}
|
|
1765
1769
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Transaction } from 'ox/tempo'
|
|
2
2
|
import { describe, expect, test } from 'vitest'
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const configurableRpcSignature =
|
|
5
5
|
'0xf89794c4a590afa7337e5cd5eb3aa60cacf91c5400044bf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d6947e5f4552091a69125d5dfcb7b8c2659029395bdf01f843b841869437e01f64bebeb78a8a6b30bfd3a993819c8cad82c807515d9b9e9b36f98535dfaa5eebc597715d05f6ce4927747f14fa4cd2acc717fdcd3877146437f8f41b' as const
|
|
6
6
|
|
|
7
7
|
describe('fromRpc', () => {
|
|
@@ -568,7 +568,7 @@ describe('toRpc', () => {
|
|
|
568
568
|
})
|
|
569
569
|
|
|
570
570
|
describe('roundtrip', () => {
|
|
571
|
-
test('behavior:
|
|
571
|
+
test('behavior: configurable RPC signature', () => {
|
|
572
572
|
const rpc = {
|
|
573
573
|
accessList: [],
|
|
574
574
|
blockHash:
|
|
@@ -583,7 +583,7 @@ describe('roundtrip', () => {
|
|
|
583
583
|
maxFeePerGas: '0x2',
|
|
584
584
|
maxPriorityFeePerGas: '0x1',
|
|
585
585
|
nonce: '0x357',
|
|
586
|
-
signature:
|
|
586
|
+
signature: configurableRpcSignature,
|
|
587
587
|
transactionIndex: '0x2',
|
|
588
588
|
type: '0x76',
|
|
589
589
|
} as const satisfies Transaction.TempoRpc
|
|
@@ -618,7 +618,7 @@ describe('roundtrip', () => {
|
|
|
618
618
|
"type": "secp256k1",
|
|
619
619
|
},
|
|
620
620
|
],
|
|
621
|
-
"type": "
|
|
621
|
+
"type": "configurable",
|
|
622
622
|
},
|
|
623
623
|
}
|
|
624
624
|
`)
|
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import { expectTypeOf, test } from 'vitest'
|
|
2
|
-
import type * as
|
|
2
|
+
import type * as AccountSimulation from './AccountSimulation.js'
|
|
3
3
|
import type * as TransactionRequest from './TransactionRequest.js'
|
|
4
4
|
|
|
5
5
|
declare const request: TransactionRequest.TransactionRequest
|
|
6
6
|
declare const rpc: TransactionRequest.Rpc
|
|
7
7
|
|
|
8
|
-
test('transaction requests use domain
|
|
9
|
-
expectTypeOf(request.
|
|
8
|
+
test('transaction requests use domain account simulation specs', () => {
|
|
9
|
+
expectTypeOf(request.accountSimulation?.config.version).toEqualTypeOf<
|
|
10
10
|
bigint | undefined
|
|
11
11
|
>()
|
|
12
12
|
|
|
13
|
-
expectTypeOf(request.
|
|
14
|
-
|
|
13
|
+
expectTypeOf(request.accountSimulation?.approvals[0]?.keyType).toEqualTypeOf<
|
|
14
|
+
AccountSimulation.PrimitiveApproval['keyType']
|
|
15
15
|
>()
|
|
16
16
|
expectTypeOf(request.keyAuthorizationSimulation).toEqualTypeOf<
|
|
17
|
-
|
|
17
|
+
AccountSimulation.Spec | undefined
|
|
18
18
|
>()
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
-
test('RPC requests use encoded
|
|
22
|
-
expectTypeOf(rpc.
|
|
21
|
+
test('RPC requests use encoded account configurations', () => {
|
|
22
|
+
expectTypeOf(rpc.configurableAccountSimulation?.config).toEqualTypeOf<
|
|
23
23
|
`0x${string}` | undefined
|
|
24
24
|
>()
|
|
25
25
|
})
|
|
26
|
+
|
|
27
|
+
test('maps the configurable key type to the RPC configurableAccount key type', () => {
|
|
28
|
+
expectTypeOf(request.keyType).toEqualTypeOf<
|
|
29
|
+
'configurable' | 'p256' | 'secp256k1' | 'webAuthn' | undefined
|
|
30
|
+
>()
|
|
31
|
+
expectTypeOf(rpc.keyType).toEqualTypeOf<
|
|
32
|
+
'configurableAccount' | 'p256' | 'secp256k1' | 'webAuthn' | undefined
|
|
33
|
+
>()
|
|
34
|
+
})
|