Skip to content

Commit 7cc9524

Browse files
authored
feat(tempo): align multisig RPC encoding (#427)
* feat(tempo): align multisig RPC encoding * fix(tempo): correct multisig tsdoc links * test(tempo): cover multisig simulation
1 parent c2b128f commit 7cc9524

23 files changed

Lines changed: 1031 additions & 804 deletions

.changeset/tidy-rpcs-simulate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'ox': patch
3+
---
4+
5+
Aligned Tempo multisig simulation requests and RPC signatures with T12's encoded wire formats.

src/tempo/AuthorizationTempo.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ describe('fromRpc', () => {
326326
type: 'p256',
327327
},
328328
})
329+
if (typeof result.signature === 'string') throw new Error('unreachable')
329330
expect(result.signature.type).toBe('p256')
330331
expect(result.signature).toHaveProperty('prehash', true)
331332
expect(result.signature).toHaveProperty('publicKey')
@@ -348,6 +349,7 @@ describe('fromRpc', () => {
348349
'0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976305000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22222c226f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c2263726f73734f726967696e223a66616c73657d',
349350
},
350351
})
352+
if (typeof result.signature === 'string') throw new Error('unreachable')
351353
expect(result.signature.type).toBe('webAuthn')
352354
expect(result.signature).toHaveProperty('metadata')
353355
expect(result.signature).toHaveProperty('publicKey')
@@ -949,6 +951,7 @@ describe('toRpc', () => {
949951
type: 'p256',
950952
},
951953
})
954+
if (typeof result.signature === 'string') throw new Error('unreachable')
952955
expect(result.signature.type).toBe('p256')
953956
})
954957

@@ -970,6 +973,7 @@ describe('toRpc', () => {
970973
type: 'webAuthn',
971974
},
972975
})
976+
if (typeof result.signature === 'string') throw new Error('unreachable')
973977
expect(result.signature.type).toBe('webAuthn')
974978
})
975979
})

src/tempo/KeyAuthorization.test-d.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,7 @@ test('accepts multisig signatures', () => {
5555
KeyAuthorization.Signed['signature']
5656
>()
5757

58-
const multisigRpc = {
59-
account: multisig.account,
60-
config: { ...multisig.config, version: 0 },
61-
signatures: [
62-
{
63-
r: '0x01',
64-
s: '0x02',
65-
type: 'secp256k1',
66-
yParity: '0x0',
67-
},
68-
],
69-
} as const satisfies SignatureEnvelope.MultisigRpc
58+
const multisigRpc = '0xf8' as const satisfies SignatureEnvelope.MultisigRpc
7059

7160
const rpc: KeyAuthorization.Rpc = {
7261
chainId: '0x1',

src/tempo/KeyAuthorization.test.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ const signature_multisig = {
6969
signatures: [SignatureEnvelope.from(signature_secp256k1)],
7070
type: 'multisig',
7171
} as const satisfies SignatureEnvelope.Multisig
72+
const signature_multisig_rpc =
73+
'0xf89794be95c3f554e9fc85ec51be69a3d807a0d55bcf2cf83ba000000000000000000000000000000000000000000000000000000000000000000101d7d694f39fd6e51aad88f6f4ce6ab8827279cfffb9226601f843b841fa78c5905fb0b9d6066ef531f962a62bc6ef0d5eb59ecb134056d206f75aaed7780926ff2601a935c2c79707d9e1799948c9f19dcdde1e090e903b19a07923d01c' as const
7274

7375
const signature_keychain = {
7476
inner: SignatureEnvelope.from(signature_secp256k1),
@@ -527,16 +529,42 @@ describe('from', () => {
527529
})
528530

529531
describe('fromRpc', () => {
530-
test('multisig', () => {
532+
test('behavior: multisig', () => {
531533
const authorization = KeyAuthorization.fromRpc({
532534
chainId: '0x1',
533535
expiry: null,
534536
keyId: address,
535537
keyType: 'secp256k1',
536-
signature: SignatureEnvelope.toRpc(signature_multisig),
538+
signature: signature_multisig_rpc,
537539
})
538540

539-
expect(authorization.signature).toEqual(signature_multisig)
541+
expect(authorization.signature).toMatchInlineSnapshot(`
542+
{
543+
"account": "0xbe95c3f554e9fc85ec51be69a3d807a0d55bcf2c",
544+
"config": {
545+
"owners": [
546+
{
547+
"owner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
548+
"weight": 1,
549+
},
550+
],
551+
"salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
552+
"threshold": 1,
553+
"version": 1n,
554+
},
555+
"signatures": [
556+
{
557+
"signature": {
558+
"r": 113291597329930009559670063131885256927775966057121513567941051428123344285399n,
559+
"s": 54293712598725100598138577281441749550405991478212695085505730636505228583888n,
560+
"yParity": 1,
561+
},
562+
"type": "secp256k1",
563+
},
564+
],
565+
"type": "multisig",
566+
}
567+
`)
540568
})
541569

542570
test('rejects a keychain signature', () => {
@@ -1340,16 +1368,16 @@ describe('serialize', () => {
13401368
})
13411369

13421370
describe('toRpc', () => {
1343-
test('multisig', () => {
1371+
test('behavior: multisig', () => {
13441372
const authorization = KeyAuthorization.toRpc({
13451373
address,
13461374
chainId: 1n,
13471375
signature: signature_multisig,
13481376
type: 'secp256k1',
13491377
})
13501378

1351-
expect(authorization.signature).toEqual(
1352-
SignatureEnvelope.toRpc(signature_multisig),
1379+
expect(authorization.signature).toMatchInlineSnapshot(
1380+
`"${signature_multisig_rpc}"`,
13531381
)
13541382
})
13551383

src/tempo/KeyAuthorization.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ export type Signature<bigintType = bigint, numberType = number> = OneOf<
9393
>
9494

9595
/** RPC-formatted signature that can authorize an access key. */
96-
export type SignatureRpc = OneOf<
97-
SignatureEnvelope.PrimitiveRpc | SignatureEnvelope.MultisigRpc
98-
>
96+
export type SignatureRpc =
97+
| SignatureEnvelope.MultisigRpc
98+
| SignatureEnvelope.PrimitiveRpc
9999

100100
/** Input type for a Key Authorization. */
101101
export type Input = KeyAuthorization<

src/tempo/MultisigOperation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ export function serializeKeyAuthorization(
287287
}
288288

289289
export declare namespace serializeKeyAuthorization {
290-
/** Options for {@link serializeKeyAuthorization}. */
290+
/** Options for `serializeKeyAuthorization`. */
291291
export type Options = {
292292
/** Root multisig account. */
293293
account: Address.Address
@@ -297,7 +297,7 @@ export declare namespace serializeKeyAuthorization {
297297
config: MultisigConfig.Config
298298
}
299299

300-
/** Error type for {@link serializeKeyAuthorization}. */
300+
/** Error type for `serializeKeyAuthorization`. */
301301
export type ErrorType =
302302
| InvalidOperationError
303303
| KeyAuthorization_.deserialize.ErrorType
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { expectTypeOf, test } from 'vitest'
2+
import * as MultisigSimulation from './MultisigSimulation.js'
3+
4+
const rpc = {
5+
account: '0x2222222222222222222222222222222222222222',
6+
approvals: [
7+
{
8+
owner: '0x1111111111111111111111111111111111111111',
9+
type: 'primitive',
10+
},
11+
],
12+
config:
13+
'0xf83ba000000000000000000000000000000000000000000000000000000000000000008001d7d694111111111111111111111111111111111111111101',
14+
} as const satisfies MultisigSimulation.Rpc
15+
16+
test('fromRpc returns a domain spec', () => {
17+
const spec = MultisigSimulation.fromRpc(rpc)
18+
19+
expectTypeOf(spec).toEqualTypeOf<MultisigSimulation.Spec>()
20+
expectTypeOf(spec.config.version).toEqualTypeOf<bigint>()
21+
})
22+
23+
test('RPC specs use encoded configurations', () => {
24+
expectTypeOf<
25+
MultisigSimulation.Rpc['config']
26+
>().toEqualTypeOf<`0x${string}`>()
27+
})
28+
29+
test('toRpc returns an RPC spec', () => {
30+
expectTypeOf(
31+
MultisigSimulation.toRpc(MultisigSimulation.fromRpc(rpc)),
32+
).toEqualTypeOf<MultisigSimulation.Rpc>()
33+
})

0 commit comments

Comments
 (0)