Skip to content

Commit 5025c36

Browse files
committed
fix(tempo): complete config witness support
1 parent c247028 commit 5025c36

9 files changed

Lines changed: 47 additions & 11 deletions

.changeset/calm-witnesses-sign.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
2-
'ox': patch
2+
'ox': minor
33
---
44

5-
Updated native multisig configurations and signatures to use TIP-1061 configuration witnesses.
5+
Changed native multisig configuration and signature APIs to require complete TIP-1061 witnesses with a `version`.
66

77
```ts
88
const config = MultisigConfig.from({

src/tempo/MultisigConfig.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ export function from<numberType = number>(
218218
export function from<numberType = number>(
219219
config: Input<bigint | number, numberType>,
220220
): Config<bigint, numberType>
221+
// eslint-disable-next-line jsdoc/require-jsdoc
221222
export function from<numberType = number>(
222223
config: Input<bigint | number, numberType>,
223224
): Config<bigint, numberType> {
@@ -606,7 +607,7 @@ export class InvalidConfigError extends Errors.BaseError {
606607
}
607608
}
608609

609-
/** Asserts that a configuration version fits the protocol's `uint64`. */
610+
/** @internal */
610611
function assertVersion(version: unknown): asserts version is bigint | number {
611612
if (
612613
(typeof version !== 'bigint' && typeof version !== 'number') ||

src/tempo/MultisigOperation.test-d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,15 @@ test('preserves operation kinds during RPC conversion', () => {
4747
})
4848

4949
test('uses JSON-RPC quantities only in RPC operations', () => {
50+
expectTypeOf<
51+
MultisigOperation.Operation['config']['version']
52+
>().toEqualTypeOf<bigint>()
5053
expectTypeOf<
5154
MultisigOperation.Operation['configVersion']
5255
>().toEqualTypeOf<bigint>()
56+
expectTypeOf<
57+
MultisigOperation.Rpc['config']['version']
58+
>().toEqualTypeOf<Hex.Hex>()
5359
expectTypeOf<
5460
MultisigOperation.Rpc['configVersion']
5561
>().toEqualTypeOf<Hex.Hex>()

src/tempo/MultisigOperation.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,9 @@ describe('RPC conversion', () => {
12691269
const transactionRpc = MultisigOperation.toRpc(transactionPending)
12701270
const keyAuthorizationRpc = MultisigOperation.toRpc(keyAuthorizationPending)
12711271

1272+
expect(() =>
1273+
JSON.stringify({ keyAuthorizationRpc, transactionRpc }),
1274+
).not.toThrow()
12721275
expect({ keyAuthorizationRpc, transactionRpc }).toMatchInlineSnapshot(`
12731276
{
12741277
"keyAuthorizationRpc": {
@@ -1289,7 +1292,7 @@ describe('RPC conversion', () => {
12891292
],
12901293
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
12911294
"threshold": 2,
1292-
"version": 1n,
1295+
"version": "0x1",
12931296
},
12941297
"configVersion": "0x1",
12951298
"createdAt": 1,
@@ -1321,7 +1324,7 @@ describe('RPC conversion', () => {
13211324
],
13221325
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
13231326
"threshold": 2,
1324-
"version": 1n,
1327+
"version": "0x1",
13251328
},
13261329
"configVersion": "0x1",
13271330
"createdAt": 1,

src/tempo/MultisigOperation.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export type Base<quantity = bigint> = {
1414
/** Every retained serialized owner approval. */
1515
approvals: readonly Hex.Hex[]
1616
/** Root configuration used to verify approvals. */
17-
config: MultisigConfig.Config
17+
config: MultisigConfig.Config<quantity>
1818
/** Root configuration version. */
1919
configVersion: quantity
2020
/** Unix creation time in milliseconds. */
@@ -403,7 +403,11 @@ export function fromRpc<const operation extends Rpc>(
403403
throw new InvalidOperationError({
404404
reason: 'configVersion must use canonical quantity encoding',
405405
})
406-
return from({ ...operation, configVersion } as Operation) as never
406+
return from({
407+
...operation,
408+
config: MultisigConfig.fromRpc(operation.config),
409+
configVersion,
410+
} as Operation) as never
407411
} catch (cause) {
408412
if (cause instanceof InvalidOperationError) throw cause
409413
throw new InvalidOperationError({ cause })
@@ -441,6 +445,7 @@ export function toRpc<const operation extends Operation>(
441445
const value = from(operation)
442446
return {
443447
...value,
448+
config: MultisigConfig.toRpc(value.config),
444449
configVersion: Hex.fromNumber(value.configVersion),
445450
} as never
446451
}

src/tempo/SignatureEnvelope.test.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3322,14 +3322,32 @@ describe('multisig', () => {
33223322
],
33233323
},
33243324
{
3325-
field: 'version',
3325+
field: 'oversized version',
33263326
value: [
33273327
('0x' + '00'.repeat(32)) as Hex.Hex,
33283328
('0x' + '01'.repeat(9)) as Hex.Hex,
33293329
'0x01',
33303330
[['0x7e5f4552091a69125d5dfcb7b8c2659029395bdf', '0x01']],
33313331
],
33323332
},
3333+
{
3334+
field: 'zero version',
3335+
value: [
3336+
('0x' + '00'.repeat(32)) as Hex.Hex,
3337+
'0x00',
3338+
'0x01',
3339+
[['0x7e5f4552091a69125d5dfcb7b8c2659029395bdf', '0x01']],
3340+
],
3341+
},
3342+
{
3343+
field: 'zero-prefixed version',
3344+
value: [
3345+
('0x' + '00'.repeat(32)) as Hex.Hex,
3346+
'0x0001',
3347+
'0x01',
3348+
[['0x7e5f4552091a69125d5dfcb7b8c2659029395bdf', '0x01']],
3349+
],
3350+
},
33333351
{
33343352
field: 'threshold',
33353353
value: [
@@ -3348,7 +3366,7 @@ describe('multisig', () => {
33483366
[['0x7e5f4552091a69125d5dfcb7b8c2659029395bdf', '0x0001']],
33493367
],
33503368
},
3351-
])('error: rejects a noncanonical $field width', ({ value }) => {
3369+
])('error: rejects a noncanonical $field', ({ value }) => {
33523370
const malformed = Hex.concat(
33533371
'0x05',
33543372
Rlp.fromHex([

src/tempo/SignatureEnvelope.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ function deserialize_(
799799
Hex.size(salt) !== 32 ||
800800
Array.isArray(version) ||
801801
Hex.size(version) > 8 ||
802+
(version !== '0x' && Hex.slice(version, 0, 1) === '0x00') ||
802803
Array.isArray(threshold) ||
803804
Hex.size(threshold) > 1 ||
804805
!Array.isArray(owners) ||

src/tempo/multisig.e2e.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as TxEnvelopeTempo from './TxEnvelopeTempo.js'
99

1010
const chainId = chain.id
1111
const updateConfig = AbiFunction.from(
12-
'function updateConfig(uint8 threshold, (address owner, uint8 weight)[] owners)',
12+
'function updateConfig((bytes32 salt, uint64 version, uint8 threshold, (address owner, uint8 weight)[] owners) current, uint8 threshold, (address owner, uint8 weight)[] owners)',
1313
)
1414

1515
describe('behavior: multisig (TIP-1061)', () => {
@@ -206,6 +206,7 @@ describe('behavior: multisig (TIP-1061)', () => {
206206
{
207207
to: '0xaacc000000000000000000000000000000000000',
208208
data: AbiFunction.encodeData(updateConfig, [
209+
initialConfig,
209210
rotatedConfig.threshold,
210211
rotatedConfig.owners,
211212
]),
@@ -713,6 +714,7 @@ describe('behavior: multisig (TIP-1061)', () => {
713714
{
714715
to: '0xaacc000000000000000000000000000000000000',
715716
data: AbiFunction.encodeData(updateConfig, [
717+
initialConfig,
716718
initialConfig.threshold,
717719
initialConfig.owners,
718720
]),

test/tempo/multisig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export const port = 3001
22

3-
export const tag = 'sha-4e74a2c'
3+
export const tag = 'sha-896b990'

0 commit comments

Comments
 (0)