ox 1.7.2 → 1.7.5

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/core/AbiEvent.d.ts.map +1 -1
  3. package/dist/core/AbiEvent.js +10 -9
  4. package/dist/core/AbiEvent.js.map +1 -1
  5. package/dist/core/Blobs.d.ts.map +1 -1
  6. package/dist/core/Blobs.js +6 -2
  7. package/dist/core/Blobs.js.map +1 -1
  8. package/dist/core/Signature.d.ts +6 -5
  9. package/dist/core/Signature.d.ts.map +1 -1
  10. package/dist/core/Signature.js +17 -7
  11. package/dist/core/Signature.js.map +1 -1
  12. package/dist/core/Siwe.d.ts.map +1 -1
  13. package/dist/core/Siwe.js +21 -1
  14. package/dist/core/Siwe.js.map +1 -1
  15. package/dist/tempo/KeyAuthorization.d.ts +43 -39
  16. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  17. package/dist/tempo/KeyAuthorization.js +24 -4
  18. package/dist/tempo/KeyAuthorization.js.map +1 -1
  19. package/dist/tempo/MultisigConfig.d.ts +18 -15
  20. package/dist/tempo/MultisigConfig.d.ts.map +1 -1
  21. package/dist/tempo/MultisigConfig.js +49 -20
  22. package/dist/tempo/MultisigConfig.js.map +1 -1
  23. package/dist/tempo/MultisigOperation.d.ts +45 -28
  24. package/dist/tempo/MultisigOperation.d.ts.map +1 -1
  25. package/dist/tempo/MultisigOperation.js +81 -131
  26. package/dist/tempo/MultisigOperation.js.map +1 -1
  27. package/dist/tempo/MultisigSimulation.d.ts +85 -0
  28. package/dist/tempo/MultisigSimulation.d.ts.map +1 -0
  29. package/dist/tempo/MultisigSimulation.js +112 -0
  30. package/dist/tempo/MultisigSimulation.js.map +1 -0
  31. package/dist/tempo/RpcSchemaTempo.d.ts +20 -10
  32. package/dist/tempo/RpcSchemaTempo.d.ts.map +1 -1
  33. package/dist/tempo/SignatureEnvelope.d.ts +74 -153
  34. package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
  35. package/dist/tempo/SignatureEnvelope.js +130 -187
  36. package/dist/tempo/SignatureEnvelope.js.map +1 -1
  37. package/dist/tempo/TransactionRequest.d.ts +9 -7
  38. package/dist/tempo/TransactionRequest.d.ts.map +1 -1
  39. package/dist/tempo/TransactionRequest.js +12 -7
  40. package/dist/tempo/TransactionRequest.js.map +1 -1
  41. package/dist/tempo/index.d.ts +7 -5
  42. package/dist/tempo/index.d.ts.map +1 -1
  43. package/dist/tempo/index.js +7 -5
  44. package/dist/tempo/index.js.map +1 -1
  45. package/dist/zod/tempo/AuthorizationTempo.d.ts +360 -140
  46. package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
  47. package/dist/zod/tempo/KeyAuthorization.d.ts +247 -487
  48. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  49. package/dist/zod/tempo/KeyAuthorization.js +29 -31
  50. package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
  51. package/dist/zod/tempo/MultisigOperation.d.ts +0 -10
  52. package/dist/zod/tempo/MultisigOperation.d.ts.map +1 -1
  53. package/dist/zod/tempo/MultisigOperation.js +0 -3
  54. package/dist/zod/tempo/MultisigOperation.js.map +1 -1
  55. package/dist/zod/tempo/MultisigSimulation.d.ts +52 -0
  56. package/dist/zod/tempo/MultisigSimulation.d.ts.map +1 -0
  57. package/dist/zod/tempo/MultisigSimulation.js +44 -0
  58. package/dist/zod/tempo/MultisigSimulation.js.map +1 -0
  59. package/dist/zod/tempo/RpcSchemaTempo.d.ts +357 -422
  60. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  61. package/dist/zod/tempo/RpcSchemaTempo.js +19 -10
  62. package/dist/zod/tempo/RpcSchemaTempo.js.map +1 -1
  63. package/dist/zod/tempo/SignatureEnvelope.d.ts +108 -42
  64. package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
  65. package/dist/zod/tempo/SignatureEnvelope.js +21 -19
  66. package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
  67. package/dist/zod/tempo/Transaction.d.ts +678 -666
  68. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  69. package/dist/zod/tempo/TransactionRequest.d.ts +580 -619
  70. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  71. package/dist/zod/tempo/TransactionRequest.js +18 -10
  72. package/dist/zod/tempo/TransactionRequest.js.map +1 -1
  73. package/dist/zod/tempo/TxEnvelopeTempo.d.ts +327 -213
  74. package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  75. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +105 -3
  76. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
  77. package/dist/zod/tempo/z.d.ts +1 -1
  78. package/dist/zod/tempo/z.d.ts.map +1 -1
  79. package/dist/zod/tempo/z.js +1 -1
  80. package/dist/zod/tempo/z.js.map +1 -1
  81. package/package.json +9 -9
  82. package/src/core/AbiEvent.ts +11 -9
  83. package/src/core/Blobs.ts +6 -2
  84. package/src/core/Signature.ts +41 -11
  85. package/src/core/Siwe.ts +20 -1
  86. package/src/core/_test/AbiEvent.test.ts +45 -0
  87. package/src/core/_test/Blobs.test.ts +22 -0
  88. package/src/core/_test/Signature.test.ts +166 -0
  89. package/src/core/_test/Siwe.test.ts +100 -1
  90. package/src/tempo/AuthorizationTempo.test.ts +8 -0
  91. package/src/tempo/KeyAuthorization.test-d.ts +16 -74
  92. package/src/tempo/KeyAuthorization.test.ts +113 -14
  93. package/src/tempo/KeyAuthorization.ts +110 -66
  94. package/src/tempo/MultisigConfig.test.ts +44 -20
  95. package/src/tempo/MultisigConfig.ts +65 -23
  96. package/src/tempo/MultisigOperation.test-d.ts +8 -6
  97. package/src/tempo/MultisigOperation.test.ts +187 -591
  98. package/src/tempo/MultisigOperation.ts +129 -205
  99. package/src/tempo/MultisigSimulation.test-d.ts +33 -0
  100. package/src/tempo/MultisigSimulation.test.ts +194 -0
  101. package/src/tempo/MultisigSimulation.ts +192 -0
  102. package/src/tempo/RpcSchemaTempo.test-d.ts +45 -10
  103. package/src/tempo/RpcSchemaTempo.ts +15 -6
  104. package/src/tempo/SignatureEnvelope.test-d.ts +27 -101
  105. package/src/tempo/SignatureEnvelope.test.ts +330 -533
  106. package/src/tempo/SignatureEnvelope.ts +198 -310
  107. package/src/tempo/Transaction.test.ts +61 -0
  108. package/src/tempo/TransactionRequest.test-d.ts +7 -7
  109. package/src/tempo/TransactionRequest.test.ts +81 -223
  110. package/src/tempo/TransactionRequest.ts +34 -13
  111. package/src/tempo/index.ts +7 -5
  112. package/src/tempo/multisig.e2e.test.ts +329 -818
  113. package/src/version.ts +1 -1
  114. package/src/zod/tempo/KeyAuthorization.ts +50 -39
  115. package/src/zod/tempo/MultisigOperation.ts +0 -3
  116. package/src/zod/tempo/MultisigSimulation.ts +53 -0
  117. package/src/zod/tempo/RpcSchemaTempo.ts +20 -10
  118. package/src/zod/tempo/SignatureEnvelope.ts +46 -59
  119. package/src/zod/tempo/TransactionRequest.ts +28 -14
  120. package/src/zod/tempo/_test/KeyAuthorization.test.ts +66 -30
  121. package/src/zod/tempo/_test/MultisigOperation.test.ts +0 -2
  122. package/src/zod/tempo/_test/MultisigSimulation.test-d.ts +13 -0
  123. package/src/zod/tempo/_test/MultisigSimulation.test.ts +53 -0
  124. package/src/zod/tempo/_test/RpcSchemaTempo.test-d.ts +19 -2
  125. package/src/zod/tempo/_test/RpcSchemaTempo.test.ts +46 -4
  126. package/src/zod/tempo/_test/SignatureEnvelope.test.ts +108 -129
  127. package/src/zod/tempo/_test/TransactionRequest.test.ts +17 -168
  128. package/src/zod/tempo/z.ts +1 -1
  129. package/dist/tempo/MultisigWitness.d.ts +0 -106
  130. package/dist/tempo/MultisigWitness.d.ts.map +0 -1
  131. package/dist/tempo/MultisigWitness.js +0 -118
  132. package/dist/tempo/MultisigWitness.js.map +0 -1
  133. package/dist/zod/tempo/MultisigWitness.d.ts +0 -152
  134. package/dist/zod/tempo/MultisigWitness.d.ts.map +0 -1
  135. package/dist/zod/tempo/MultisigWitness.js +0 -76
  136. package/dist/zod/tempo/MultisigWitness.js.map +0 -1
  137. package/src/tempo/MultisigWitness.test-d.ts +0 -42
  138. package/src/tempo/MultisigWitness.test.ts +0 -288
  139. package/src/tempo/MultisigWitness.ts +0 -210
  140. package/src/zod/tempo/MultisigWitness.ts +0 -101
  141. package/src/zod/tempo/_test/MultisigWitness.test-d.ts +0 -13
  142. package/src/zod/tempo/_test/MultisigWitness.test.ts +0 -149
@@ -0,0 +1,194 @@
1
+ import { MultisigConfig, MultisigSimulation } from 'ox/tempo'
2
+ import { describe, expect, test } from 'vp/test'
3
+
4
+ const config =
5
+ '0xf852a011111111111111111111111111111111111111111111111111111111111111118002eed694111111111111111111111111111111111111111101d694bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01' as const
6
+ const rpc = {
7
+ approvals: [
8
+ {
9
+ keyType: 'webAuthn',
10
+ keyData: '0x0102030405',
11
+ owner: '0x1111111111111111111111111111111111111111',
12
+ },
13
+ ],
14
+ config,
15
+ } as const satisfies MultisigSimulation.Rpc
16
+
17
+ describe('fromRpc', () => {
18
+ test('behavior: decodes the configuration', () => {
19
+ expect(MultisigSimulation.fromRpc(rpc)).toMatchInlineSnapshot(`
20
+ {
21
+ "approvals": [
22
+ {
23
+ "keyData": "0x0102030405",
24
+ "keyType": "webAuthn",
25
+ "owner": "0x1111111111111111111111111111111111111111",
26
+ },
27
+ ],
28
+ "config": {
29
+ "owners": [
30
+ {
31
+ "owner": "0x1111111111111111111111111111111111111111",
32
+ "weight": 1,
33
+ },
34
+ {
35
+ "owner": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
36
+ "weight": 1,
37
+ },
38
+ ],
39
+ "salt": "0x1111111111111111111111111111111111111111111111111111111111111111",
40
+ "threshold": 2,
41
+ "version": 0n,
42
+ },
43
+ }
44
+ `)
45
+ })
46
+
47
+ test('behavior: preserves the maximum uint64 configuration version', () => {
48
+ const config =
49
+ '0xf843a0000000000000000000000000000000000000000000000000000000000000000088ffffffffffffffff01d7d694111111111111111111111111111111111111111101' as const
50
+
51
+ expect(
52
+ MultisigSimulation.fromRpc({ ...rpc, approvals: [], config }).config
53
+ .version,
54
+ ).toMatchInlineSnapshot(`18446744073709551615n`)
55
+ })
56
+
57
+ test('error: rejects excess root approvals', () => {
58
+ expect(() =>
59
+ MultisigSimulation.fromRpc({
60
+ ...rpc,
61
+ approvals: Array.from({ length: 9 }, () => rpc.approvals[0]),
62
+ }),
63
+ ).toThrowErrorMatchingInlineSnapshot(
64
+ `[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: approval count exceeds 8.]`,
65
+ )
66
+ })
67
+ test('error: rejects nested approvals', () => {
68
+ expect(() =>
69
+ MultisigSimulation.fromRpc({
70
+ ...rpc,
71
+ approvals: [{ type: 'multisig', spec: rpc }],
72
+ } as never),
73
+ ).toThrowErrorMatchingInlineSnapshot(
74
+ `[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: only untagged primitive owner approvals are allowed.]`,
75
+ )
76
+ })
77
+
78
+ test('error: rejects trailing configuration bytes', () => {
79
+ expect(() =>
80
+ MultisigSimulation.fromRpc({ ...rpc, config: `${config}00` }),
81
+ ).toThrowErrorMatchingInlineSnapshot(
82
+ `[Rlp.TrailingBytesError: RLP payload encodes a single item, but \`1\` trailing byte remains.]`,
83
+ )
84
+ })
85
+
86
+ test('error: rejects malformed configuration RLP', () => {
87
+ expect(() =>
88
+ MultisigSimulation.fromRpc({ ...rpc, config: '0xf8' }),
89
+ ).toThrowErrorMatchingInlineSnapshot(
90
+ `[Cursor.PositionOutOfBoundsError: Position \`1\` is out of bounds (\`0 < position < 1\`).]`,
91
+ )
92
+ })
93
+
94
+ test('error: rejects a non-list configuration', () => {
95
+ expect(() =>
96
+ MultisigSimulation.fromRpc({ ...rpc, config: '0x01' }),
97
+ ).toThrowErrorMatchingInlineSnapshot(
98
+ `[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: invalid config encoding.]`,
99
+ )
100
+ })
101
+
102
+ test('error: rejects noncanonical configuration integers', () => {
103
+ const noncanonical = config
104
+ .replace('0xf852', '0xf853')
105
+ .replace('118002', '11810002') as `0x${string}`
106
+
107
+ expect(() =>
108
+ MultisigSimulation.fromRpc({ ...rpc, config: noncanonical }),
109
+ ).toThrowErrorMatchingInlineSnapshot(
110
+ `[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: invalid config encoding.]`,
111
+ )
112
+ })
113
+ })
114
+
115
+ describe('toRpc', () => {
116
+ test('behavior: encodes configurations and shims long key data', () => {
117
+ expect(MultisigSimulation.toRpc(MultisigSimulation.fromRpc(rpc)))
118
+ .toMatchInlineSnapshot(`
119
+ {
120
+ "approvals": [
121
+ {
122
+ "keyData": "0x0005",
123
+ "keyType": "webAuthn",
124
+ "owner": "0x1111111111111111111111111111111111111111",
125
+ },
126
+ ],
127
+ "config": "0xf852a011111111111111111111111111111111111111111111111111111111111111118002eed694111111111111111111111111111111111111111101d694bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01",
128
+ }
129
+ `)
130
+ })
131
+
132
+ test('behavior: preserves short key data', () => {
133
+ const spec = MultisigSimulation.fromRpc({
134
+ ...rpc,
135
+ approvals: [{ ...rpc.approvals[0], keyData: '0x0102' }],
136
+ })
137
+
138
+ expect(MultisigSimulation.toRpc(spec).approvals).toMatchInlineSnapshot(`
139
+ [
140
+ {
141
+ "keyData": "0x0102",
142
+ "keyType": "webAuthn",
143
+ "owner": "0x1111111111111111111111111111111111111111",
144
+ },
145
+ ]
146
+ `)
147
+ })
148
+
149
+ test('behavior: encodes the maximum uint64 configuration version', () => {
150
+ const spec = MultisigSimulation.fromRpc(rpc)
151
+
152
+ expect(
153
+ MultisigSimulation.toRpc({
154
+ ...spec,
155
+ approvals: [],
156
+ config: MultisigConfig.from({
157
+ owners: [
158
+ {
159
+ owner: '0x1111111111111111111111111111111111111111',
160
+ weight: 1,
161
+ },
162
+ ],
163
+ threshold: 1,
164
+ version: MultisigConfig.maxVersion,
165
+ }),
166
+ }).config,
167
+ ).toMatchInlineSnapshot(
168
+ `"0xf843a0000000000000000000000000000000000000000000000000000000000000000088ffffffffffffffff01d7d694111111111111111111111111111111111111111101"`,
169
+ )
170
+ })
171
+
172
+ test('error: rejects excess root approvals', () => {
173
+ const spec = MultisigSimulation.fromRpc(rpc)
174
+
175
+ expect(() =>
176
+ MultisigSimulation.toRpc({
177
+ ...spec,
178
+ approvals: Array.from({ length: 9 }, () => spec.approvals[0]!),
179
+ }),
180
+ ).toThrowErrorMatchingInlineSnapshot(
181
+ `[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: approval count exceeds 8.]`,
182
+ )
183
+ })
184
+ test('error: rejects nested approvals', () => {
185
+ expect(() =>
186
+ MultisigSimulation.toRpc({
187
+ ...rpc,
188
+ approvals: [{ type: 'multisig', spec: rpc }],
189
+ } as never),
190
+ ).toThrowErrorMatchingInlineSnapshot(
191
+ `[MultisigSimulation.InvalidSimulationError: Invalid multisig simulation: only untagged primitive owner approvals are allowed.]`,
192
+ )
193
+ })
194
+ })
@@ -0,0 +1,192 @@
1
+ import * as Address from '../core/Address.js'
2
+ import * as Errors from '../core/Errors.js'
3
+ import * as Hex from '../core/Hex.js'
4
+ import type { Compute } from '../core/internal/types.js'
5
+ import * as Rlp from '../core/Rlp.js'
6
+ import * as MultisigConfig from './MultisigConfig.js'
7
+ import type * as SignatureEnvelope from './SignatureEnvelope.js'
8
+
9
+ /** Native multisig owner approval used for RPC simulation. */
10
+ export type Approval = PrimitiveApproval
11
+
12
+ /** JSON-RPC native multisig owner approval used for RPC simulation. */
13
+ export type ApprovalRpc = PrimitiveApproval
14
+
15
+ /** Primitive owner approval used for RPC simulation. */
16
+ export type PrimitiveApproval = {
17
+ /** Optional signature-specific gas-estimation data. */
18
+ keyData?: Hex.Hex | undefined
19
+ /** Signature type to model. Omission uses a maximum-size WebAuthn signature. */
20
+ keyType?: SignatureEnvelope.Type | undefined
21
+ /** Configured owner address. */
22
+ owner: Address.Address
23
+ }
24
+
25
+ /** JSON-RPC representation of a native multisig simulation spec. */
26
+ export type Rpc = Compute<{
27
+ /** Owner approvals to model. */
28
+ approvals: readonly ApprovalRpc[]
29
+ /** Canonical RLP-encoded applicable configuration. */
30
+ config: Hex.Hex
31
+ }>
32
+
33
+ /** Native multisig spec used to construct an RPC simulation signature. */
34
+ export type Spec = Compute<{
35
+ /** Owner approvals to model. */
36
+ approvals: readonly Approval[]
37
+ /** Complete applicable configuration. */
38
+ config: MultisigConfig.Config
39
+ }>
40
+
41
+ /**
42
+ * Converts a JSON-RPC multisig simulation spec to its domain representation.
43
+ *
44
+ * @example
45
+ * ```ts twoslash
46
+ * // @noErrors
47
+ * import { MultisigSimulation } from 'ox/tempo'
48
+ *
49
+ * const spec = MultisigSimulation.fromRpc(specRpc)
50
+ * ```
51
+ *
52
+ * @param spec - JSON-RPC multisig simulation spec.
53
+ * @returns The multisig simulation spec with decoded configurations.
54
+ */
55
+ export function fromRpc(spec: Rpc): Spec {
56
+ const { approvals, config } = spec
57
+ assertApprovals(approvals)
58
+ return { approvals, config: deserializeConfig(config) }
59
+ }
60
+
61
+ export declare namespace fromRpc {
62
+ /** Error type for `fromRpc`. */
63
+ export type ErrorType =
64
+ | Hex.isEqual.ErrorType
65
+ | InvalidSimulationError
66
+ | MultisigConfig.assert.ErrorType
67
+ | Rlp.fromHex.ErrorType
68
+ | Rlp.toHex.ErrorType
69
+ | Errors.GlobalErrorType
70
+ }
71
+
72
+ /**
73
+ * Converts a multisig simulation spec to its JSON-RPC representation.
74
+ *
75
+ * @example
76
+ * ```ts twoslash
77
+ * // @noErrors
78
+ * import { MultisigSimulation } from 'ox/tempo'
79
+ *
80
+ * const specRpc = MultisigSimulation.toRpc(spec)
81
+ * ```
82
+ *
83
+ * @param spec - Multisig simulation spec.
84
+ * @returns The JSON-RPC multisig simulation spec with encoded configurations.
85
+ */
86
+ export function toRpc(spec: Spec): Rpc {
87
+ const { approvals, config } = spec
88
+ assertApprovals(approvals)
89
+ return {
90
+ approvals: approvals.map(({ keyData, keyType, owner }) => ({
91
+ ...(keyData !== undefined ? { keyData: shimKeyData(keyData) } : {}),
92
+ ...(keyType !== undefined ? { keyType } : {}),
93
+ owner,
94
+ })),
95
+ config: serializeConfig(config),
96
+ }
97
+ }
98
+
99
+ export declare namespace toRpc {
100
+ /** Error type for `toRpc`. */
101
+ export type ErrorType =
102
+ | Hex.fromNumber.ErrorType
103
+ | InvalidSimulationError
104
+ | MultisigConfig.assert.ErrorType
105
+ | Rlp.fromHex.ErrorType
106
+ | Errors.GlobalErrorType
107
+ }
108
+
109
+ /** @internal */
110
+ function assertApprovals(approvals: readonly unknown[]) {
111
+ if (
112
+ approvals.some(
113
+ (approval) =>
114
+ typeof approval !== 'object' ||
115
+ approval === null ||
116
+ 'spec' in approval ||
117
+ 'type' in approval,
118
+ )
119
+ )
120
+ throw new InvalidSimulationError({
121
+ reason: 'only untagged primitive owner approvals are allowed',
122
+ })
123
+ if (approvals.length > MultisigConfig.maxSignatures)
124
+ throw new InvalidSimulationError({
125
+ reason: `approval count exceeds ${MultisigConfig.maxSignatures}`,
126
+ })
127
+ }
128
+
129
+ /** @internal */
130
+ function deserializeConfig(config: Hex.Hex): MultisigConfig.Config {
131
+ const tuple = Rlp.toHex(config)
132
+ if (!Array.isArray(tuple) || tuple.length !== 4)
133
+ throw new InvalidSimulationError({ reason: 'invalid config encoding' })
134
+ const [salt, version, threshold, owners] = tuple
135
+ if (
136
+ Array.isArray(salt) ||
137
+ Hex.size(salt) !== 32 ||
138
+ Array.isArray(version) ||
139
+ Hex.size(version) > 8 ||
140
+ (version !== '0x' && Hex.slice(version, 0, 1) === '0x00') ||
141
+ Array.isArray(threshold) ||
142
+ Hex.size(threshold) > 1 ||
143
+ !Array.isArray(owners) ||
144
+ owners.some(
145
+ (owner) =>
146
+ !Array.isArray(owner) ||
147
+ owner.length !== 2 ||
148
+ owner.some(Array.isArray) ||
149
+ !Address.validate(owner[0]) ||
150
+ Hex.size(owner[1] as Hex.Hex) > 1,
151
+ )
152
+ )
153
+ throw new InvalidSimulationError({ reason: 'invalid config encoding' })
154
+ const value = MultisigConfig.fromTuple(
155
+ tuple as unknown as MultisigConfig.Tuple,
156
+ )
157
+ MultisigConfig.assert(value)
158
+ if (!Hex.isEqual(config, serializeConfig(value)))
159
+ throw new InvalidSimulationError({ reason: 'noncanonical config encoding' })
160
+ return value
161
+ }
162
+
163
+ /** @internal */
164
+ function serializeConfig(config: MultisigConfig.Input): Hex.Hex {
165
+ return Rlp.fromHex(MultisigConfig.toTuple(config))
166
+ }
167
+
168
+ /**
169
+ * Shims long key data into the length hint accepted by Tempo's gas estimator.
170
+ * @internal
171
+ */
172
+ function shimKeyData(data: Hex.Hex): Hex.Hex {
173
+ const size = Hex.size(data)
174
+ if (size <= 4) return data
175
+ return Hex.fromNumber(size, { size: 2 })
176
+ }
177
+
178
+ /** Thrown when a native multisig simulation spec is invalid. */
179
+ export class InvalidSimulationError extends Errors.BaseError {
180
+ override readonly name = 'MultisigSimulation.InvalidSimulationError'
181
+ constructor(options: InvalidSimulationError.Options) {
182
+ super(`Invalid multisig simulation: ${options.reason}.`)
183
+ }
184
+ }
185
+
186
+ export declare namespace InvalidSimulationError {
187
+ /** Error construction options. */
188
+ export type Options = {
189
+ /** Validation failure. */
190
+ reason: string
191
+ }
192
+ }
@@ -1,19 +1,41 @@
1
1
  import type { Provider } from 'ox'
2
2
  import type {
3
3
  KeyAuthorization,
4
+ MultisigConfig,
4
5
  MultisigOperation,
6
+ MultisigSimulation,
5
7
  RpcSchemaTempo,
6
8
  } from 'ox/tempo'
7
9
  import { expectTypeOf, test } from 'vp/test'
10
+ import type * as Address from '../core/Address.js'
8
11
  import type * as Hex from '../core/Hex.js'
9
12
 
10
13
  declare const provider: Provider.Provider<{ schema: RpcSchemaTempo.Multisig }>
14
+ declare const tempoProvider: Provider.Provider<{
15
+ schema: RpcSchemaTempo.Tempo
16
+ }>
17
+ declare const address: Address.Address
11
18
  declare const hash: Hex.Hex
12
19
  declare const keyAuthorization: KeyAuthorization.Rpc
20
+ declare const multisigSimulation: MultisigSimulation.Rpc
13
21
  declare const serializedTransaction: Hex.Hex
14
22
  declare const signature: Hex.Hex
15
23
 
16
24
  test('multisig provider methods', () => {
25
+ expectTypeOf(
26
+ provider.request({
27
+ method: 'multisig_approveKeyAuthorization',
28
+ params: [{ keyAuthorization }],
29
+ }),
30
+ ).resolves.toEqualTypeOf<MultisigOperation.KeyAuthorizationRpc>()
31
+
32
+ expectTypeOf(
33
+ provider.request({
34
+ method: 'multisig_approveKeyAuthorization',
35
+ params: [{ hash, signature }],
36
+ }),
37
+ ).resolves.toEqualTypeOf<MultisigOperation.KeyAuthorizationRpc>()
38
+
17
39
  expectTypeOf(
18
40
  provider.request({
19
41
  method: 'multisig_approveRawTransaction',
@@ -35,17 +57,10 @@ test('multisig provider methods', () => {
35
57
 
36
58
  expectTypeOf(
37
59
  provider.request({
38
- method: 'multisig_approveKeyAuthorization',
39
- params: [{ keyAuthorization }],
60
+ method: 'multisig_getConfig',
61
+ params: [{ address }],
40
62
  }),
41
- ).resolves.toEqualTypeOf<MultisigOperation.KeyAuthorizationRpc>()
42
-
43
- expectTypeOf(
44
- provider.request({
45
- method: 'multisig_approveKeyAuthorization',
46
- params: [{ hash, signature }],
47
- }),
48
- ).resolves.toEqualTypeOf<MultisigOperation.KeyAuthorizationRpc>()
63
+ ).resolves.toEqualTypeOf<MultisigConfig.Rpc | null>()
49
64
 
50
65
  expectTypeOf(
51
66
  provider.request({
@@ -54,3 +69,23 @@ test('multisig provider methods', () => {
54
69
  }),
55
70
  ).resolves.toEqualTypeOf<MultisigOperation.Rpc | null>()
56
71
  })
72
+
73
+ test('tempo simulation accepts multisig specs', () => {
74
+ void tempoProvider.request({
75
+ method: 'tempo_simulateV1',
76
+ params: [
77
+ {
78
+ blockStateCalls: [
79
+ {
80
+ calls: [
81
+ {
82
+ multisigSimulation,
83
+ },
84
+ ],
85
+ },
86
+ ],
87
+ },
88
+ 'latest',
89
+ ],
90
+ })
91
+ })
@@ -1,3 +1,4 @@
1
+ import type * as Address from '../core/Address.js'
1
2
  import type * as Block from '../core/Block.js'
2
3
  import type * as BlockOverrides from '../core/BlockOverrides.js'
3
4
  import type * as Hex from '../core/Hex.js'
@@ -5,6 +6,7 @@ import type * as Log from '../core/Log.js'
5
6
  import type * as RpcSchema from '../core/RpcSchema.js'
6
7
  import type * as StateOverrides from '../core/StateOverrides.js'
7
8
  import type * as KeyAuthorization from './KeyAuthorization.js'
9
+ import type * as MultisigConfig from './MultisigConfig.js'
8
10
  import type * as MultisigOperation from './MultisigOperation.js'
9
11
  import type * as TransactionRequest from './TransactionRequest.js'
10
12
 
@@ -58,6 +60,16 @@ export type Tempo = RpcSchema.From<{
58
60
 
59
61
  /** Union of all JSON-RPC methods for the `multisig_` namespace. */
60
62
  export type Multisig = RpcSchema.From<
63
+ | {
64
+ Request: {
65
+ method: 'multisig_approveKeyAuthorization'
66
+ params: [
67
+ | { keyAuthorization: KeyAuthorization.Rpc }
68
+ | { hash: Hex.Hex; signature: Hex.Hex },
69
+ ]
70
+ }
71
+ ReturnType: MultisigOperation.KeyAuthorizationRpc
72
+ }
61
73
  | {
62
74
  Request: {
63
75
  method: 'multisig_approveRawTransaction'
@@ -74,13 +86,10 @@ export type Multisig = RpcSchema.From<
74
86
  }
75
87
  | {
76
88
  Request: {
77
- method: 'multisig_approveKeyAuthorization'
78
- params: [
79
- | { keyAuthorization: KeyAuthorization.Rpc }
80
- | { hash: Hex.Hex; signature: Hex.Hex },
81
- ]
89
+ method: 'multisig_getConfig'
90
+ params: [{ address: Address.Address }]
82
91
  }
83
- ReturnType: MultisigOperation.KeyAuthorizationRpc
92
+ ReturnType: MultisigConfig.Rpc | null
84
93
  }
85
94
  | {
86
95
  Request: {
@@ -1,114 +1,40 @@
1
1
  import { expectTypeOf, test } from 'vp/test'
2
- import * as MultisigConfig from './MultisigConfig.js'
2
+ import type * as Hex from '../core/Hex.js'
3
3
  import * as SignatureEnvelope from './SignatureEnvelope.js'
4
4
 
5
- const signatureRpc = {
6
- r: '0x01',
7
- s: '0x02',
8
- type: 'secp256k1',
9
- yParity: '0x0',
10
- } as const satisfies SignatureEnvelope.SignatureEnvelopeRpc
11
-
12
- const signature = {
13
- signature: {
14
- r: '0x01',
15
- s: '0x02',
16
- yParity: 0,
5
+ const primitive = SignatureEnvelope.from({ r: '0x01', s: '0x02', yParity: 0 })
6
+ const envelope = SignatureEnvelope.from({
7
+ account: '0x2222222222222222222222222222222222222222',
8
+ config: {
9
+ threshold: 1,
10
+ version: 0n,
11
+ owners: [
12
+ { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
13
+ ],
17
14
  },
18
- type: 'secp256k1',
19
- } as const satisfies SignatureEnvelope.Secp256k1
20
-
21
- const config = MultisigConfig.from({
22
- owners: [
23
- {
24
- owner: '0x1111111111111111111111111111111111111111',
25
- weight: 1,
26
- },
27
- ],
28
- threshold: 1,
15
+ signatures: [primitive],
29
16
  })
30
17
 
31
- test('toRpc preserves the signature type', () => {
18
+ test('preserves primitive and multisig RPC types', () => {
32
19
  expectTypeOf(
33
- SignatureEnvelope.toRpc(signature),
20
+ SignatureEnvelope.toRpc(primitive),
34
21
  ).toEqualTypeOf<SignatureEnvelope.Secp256k1Rpc>()
35
- })
36
-
37
- test('MultisigRpc carries one complete witness shape', () => {
38
- const rpc = {
39
- account: '0x1111111111111111111111111111111111111111',
40
- config: MultisigConfig.toRpc(config),
41
- signatures: [signatureRpc],
42
- } as const satisfies SignatureEnvelope.MultisigRpc
43
-
44
- expectTypeOf(rpc.config).toMatchTypeOf<MultisigConfig.Rpc>()
45
- expectTypeOf(rpc.signatures).toMatchTypeOf<
46
- readonly SignatureEnvelope.SignatureEnvelopeRpc[]
47
- >()
22
+ expectTypeOf(SignatureEnvelope.toRpc(envelope)).toEqualTypeOf<Hex.Hex>()
48
23
  expectTypeOf<
49
- SignatureEnvelope.GetType<typeof rpc>
24
+ SignatureEnvelope.GetType<typeof envelope>
50
25
  >().toEqualTypeOf<'multisig'>()
26
+ expectTypeOf(envelope).toMatchTypeOf<SignatureEnvelope.Multisig>()
51
27
  })
52
28
 
53
- test('from derives an initial account', () => {
54
- const multisig = SignatureEnvelope.from({
55
- config,
56
- signatures: [signature],
57
- })
58
-
59
- expectTypeOf(multisig).toMatchTypeOf<SignatureEnvelope.Multisig>()
60
- expectTypeOf(multisig.config.version).toEqualTypeOf<bigint>()
61
- })
62
-
63
- test('from requires an account for a current config', () => {
64
- // @ts-expect-error Current configurations require an explicit account.
65
- SignatureEnvelope.from({
66
- config: { ...config, version: 1 },
67
- signatures: [signature],
68
- })
69
-
70
- const multisig = SignatureEnvelope.from({
71
- account: '0x2222222222222222222222222222222222222222',
72
- config: { ...config, version: 1 },
73
- signatures: [signature],
74
- })
75
- expectTypeOf(multisig).toMatchTypeOf<SignatureEnvelope.Multisig>()
76
- })
77
-
78
- test('MultisigRpc rejects old witness shapes', () => {
79
- const accountOnly = {
80
- account: '0x1111111111111111111111111111111111111111',
81
- signatures: [signatureRpc],
82
- } as const
83
- // @ts-expect-error Multisig RPC signatures require config.
84
- const accountOnlyRpc: SignatureEnvelope.MultisigRpc = accountOnly
85
-
86
- const init = {
87
- init: config,
88
- signatures: [signatureRpc],
89
- } as const
90
- // @ts-expect-error Multisig RPC signatures no longer accept init.
91
- const initRpc: SignatureEnvelope.MultisigRpc = init
92
-
93
- const serialized = {
94
- account: '0x1111111111111111111111111111111111111111',
95
- config: MultisigConfig.toRpc(config),
96
- signatures: ['0x1234'],
97
- } as const
98
- // @ts-expect-error Owner approvals use structured RPC envelopes.
99
- const serializedRpc: SignatureEnvelope.MultisigRpc = serialized
100
-
101
- const tagged = {
102
- account: '0x1111111111111111111111111111111111111111',
103
- config: MultisigConfig.toRpc(config),
104
- signatures: [signatureRpc],
105
- type: 'multisig',
106
- } as const
107
- // @ts-expect-error Multisig RPC signatures are untagged.
108
- const taggedRpc: SignatureEnvelope.MultisigRpc = tagged
109
-
110
- expectTypeOf(accountOnlyRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
111
- expectTypeOf(initRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
112
- expectTypeOf(serializedRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
113
- expectTypeOf(taggedRpc).toEqualTypeOf<SignatureEnvelope.MultisigRpc>()
29
+ test('requires config and primitive approvals', () => {
30
+ // @ts-expect-error Every multisig signature carries its current config.
31
+ SignatureEnvelope.from({ account: envelope.account, signatures: [primitive] })
32
+ // @ts-expect-error Multisig owners cannot recursively approve with multisigs.
33
+ SignatureEnvelope.from({ ...envelope, signatures: [envelope] })
34
+ // @ts-expect-error Multisig RPC signatures are hex-encoded RLP.
35
+ const rpc: SignatureEnvelope.MultisigRpc = {
36
+ account: envelope.account,
37
+ signatures: [],
38
+ }
39
+ expectTypeOf(rpc).toEqualTypeOf<Hex.Hex>()
114
40
  })