ox 1.7.4 → 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 (105) hide show
  1. package/CHANGELOG.md +16 -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 +42 -38
  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 +3 -2
  24. package/dist/tempo/MultisigOperation.d.ts.map +1 -1
  25. package/dist/tempo/MultisigOperation.js +20 -100
  26. package/dist/tempo/MultisigOperation.js.map +1 -1
  27. package/dist/tempo/MultisigSimulation.d.ts +2 -49
  28. package/dist/tempo/MultisigSimulation.d.ts.map +1 -1
  29. package/dist/tempo/MultisigSimulation.js +18 -46
  30. package/dist/tempo/MultisigSimulation.js.map +1 -1
  31. package/dist/tempo/SignatureEnvelope.d.ts +72 -140
  32. package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
  33. package/dist/tempo/SignatureEnvelope.js +130 -181
  34. package/dist/tempo/SignatureEnvelope.js.map +1 -1
  35. package/dist/tempo/TransactionRequest.d.ts +4 -2
  36. package/dist/tempo/TransactionRequest.d.ts.map +1 -1
  37. package/dist/tempo/TransactionRequest.js +6 -1
  38. package/dist/tempo/TransactionRequest.js.map +1 -1
  39. package/dist/tempo/index.d.ts +3 -1
  40. package/dist/tempo/index.d.ts.map +1 -1
  41. package/dist/tempo/index.js +3 -1
  42. package/dist/tempo/index.js.map +1 -1
  43. package/dist/zod/tempo/AuthorizationTempo.d.ts +350 -10
  44. package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
  45. package/dist/zod/tempo/KeyAuthorization.d.ts +242 -422
  46. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  47. package/dist/zod/tempo/KeyAuthorization.js +29 -31
  48. package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
  49. package/dist/zod/tempo/MultisigSimulation.d.ts +8 -76
  50. package/dist/zod/tempo/MultisigSimulation.d.ts.map +1 -1
  51. package/dist/zod/tempo/MultisigSimulation.js +3 -37
  52. package/dist/zod/tempo/MultisigSimulation.js.map +1 -1
  53. package/dist/zod/tempo/RpcSchemaTempo.d.ts +284 -228
  54. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  55. package/dist/zod/tempo/SignatureEnvelope.d.ts +105 -3
  56. package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
  57. package/dist/zod/tempo/SignatureEnvelope.js +21 -9
  58. package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
  59. package/dist/zod/tempo/Transaction.d.ts +676 -448
  60. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  61. package/dist/zod/tempo/TransactionRequest.d.ts +590 -473
  62. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  63. package/dist/zod/tempo/TransactionRequest.js +8 -0
  64. package/dist/zod/tempo/TransactionRequest.js.map +1 -1
  65. package/dist/zod/tempo/TxEnvelopeTempo.d.ts +327 -213
  66. package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  67. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +105 -3
  68. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
  69. package/package.json +1 -1
  70. package/src/core/AbiEvent.ts +11 -9
  71. package/src/core/Blobs.ts +6 -2
  72. package/src/core/Signature.ts +41 -11
  73. package/src/core/Siwe.ts +20 -1
  74. package/src/core/_test/AbiEvent.test.ts +45 -0
  75. package/src/core/_test/Blobs.test.ts +22 -0
  76. package/src/core/_test/Signature.test.ts +166 -0
  77. package/src/core/_test/Siwe.test.ts +100 -1
  78. package/src/tempo/AuthorizationTempo.test.ts +8 -4
  79. package/src/tempo/KeyAuthorization.test-d.ts +16 -63
  80. package/src/tempo/KeyAuthorization.test.ts +69 -11
  81. package/src/tempo/KeyAuthorization.ts +107 -63
  82. package/src/tempo/MultisigConfig.test.ts +44 -20
  83. package/src/tempo/MultisigConfig.ts +65 -23
  84. package/src/tempo/MultisigOperation.test.ts +79 -550
  85. package/src/tempo/MultisigOperation.ts +31 -146
  86. package/src/tempo/MultisigSimulation.test-d.ts +2 -2
  87. package/src/tempo/MultisigSimulation.test.ts +21 -110
  88. package/src/tempo/MultisigSimulation.ts +25 -99
  89. package/src/tempo/SignatureEnvelope.test-d.ts +29 -47
  90. package/src/tempo/SignatureEnvelope.test.ts +328 -541
  91. package/src/tempo/SignatureEnvelope.ts +196 -291
  92. package/src/tempo/Transaction.test.ts +4 -4
  93. package/src/tempo/TransactionRequest.test.ts +17 -80
  94. package/src/tempo/TransactionRequest.ts +19 -2
  95. package/src/tempo/index.ts +3 -1
  96. package/src/tempo/multisig.e2e.test.ts +321 -860
  97. package/src/version.ts +1 -1
  98. package/src/zod/tempo/KeyAuthorization.ts +50 -39
  99. package/src/zod/tempo/MultisigSimulation.ts +3 -48
  100. package/src/zod/tempo/SignatureEnvelope.ts +46 -35
  101. package/src/zod/tempo/TransactionRequest.ts +14 -0
  102. package/src/zod/tempo/_test/KeyAuthorization.test.ts +69 -20
  103. package/src/zod/tempo/_test/MultisigSimulation.test.ts +6 -31
  104. package/src/zod/tempo/_test/SignatureEnvelope.test.ts +118 -85
  105. package/src/zod/tempo/_test/TransactionRequest.test.ts +9 -19
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** @internal */
2
- export const version = '1.7.4'
2
+ export const version = '1.7.5'
@@ -9,16 +9,6 @@ import {
9
9
  import * as z from 'zod/mini'
10
10
  import * as z_SignatureEnvelope from './SignatureEnvelope.js'
11
11
 
12
- const SignatureRpc = z.union([
13
- z_SignatureEnvelope.PrimitiveRpc,
14
- z_SignatureEnvelope.MultisigRpc,
15
- ])
16
-
17
- const Signature = z.union([
18
- z_SignatureEnvelope.Primitive,
19
- z_SignatureEnvelope.Multisig,
20
- ])
21
-
22
12
  /** RPC token spending limit schema. */
23
13
  export const RpcTokenLimit = z.object({
24
14
  limit: z_Hex.Hex,
@@ -39,18 +29,28 @@ export const RpcCallScope = z.object({
39
29
  })
40
30
 
41
31
  /** RPC key authorization schema. */
42
- export const Rpc = z.object({
43
- account: z.optional(z.nullable(z_Address.Address)),
44
- allowedCalls: z.optional(z.nullable(z.readonly(z.array(RpcCallScope)))),
45
- chainId: z_Hex.Hex,
46
- expiry: z.optional(z.nullable(z_Hex.Hex)),
47
- isAdmin: z.optional(z.nullable(z.boolean())),
48
- keyId: z_Address.Address,
49
- keyType: z_SignatureEnvelope.Type,
50
- limits: z.optional(z.nullable(z.readonly(z.array(RpcTokenLimit)))),
51
- signature: SignatureRpc,
52
- witness: z.optional(z.nullable(z_Hex.Hex)),
53
- })
32
+ export const Rpc = z
33
+ .object({
34
+ account: z.optional(z.nullable(z_Address.Address)),
35
+ allowedCalls: z.optional(z.nullable(z.readonly(z.array(RpcCallScope)))),
36
+ chainId: z_Hex.Hex,
37
+ expiry: z.optional(z.nullable(z_Hex.Hex)),
38
+ isAdmin: z.optional(z.nullable(z.boolean())),
39
+ keyId: z_Address.Address,
40
+ keyType: z.union([z_SignatureEnvelope.Type, z.literal('multisig')]),
41
+ limits: z.optional(z.nullable(z.readonly(z.array(RpcTokenLimit)))),
42
+ signature: z.union([
43
+ z_SignatureEnvelope.PrimitiveRpc,
44
+ z_SignatureEnvelope.MultisigRpc,
45
+ ]),
46
+ witness: z.optional(z.nullable(z_Hex.Hex)),
47
+ })
48
+ .check(
49
+ z.refine(
50
+ (value) => value.keyType !== 'multisig' || value.account != null,
51
+ 'multisig key grants require a parent account binding',
52
+ ),
53
+ )
54
54
 
55
55
  /** Token spending limit schema. */
56
56
  export const TokenLimit = z.object({
@@ -79,20 +79,27 @@ const domainShape = {
79
79
  expiry: z.optional(z.number()),
80
80
  limits: z.optional(z.readonly(z.array(TokenLimit))),
81
81
  scopes: z.optional(z.readonly(z.array(Scope))),
82
- signature: Signature,
83
- type: z_SignatureEnvelope.Type,
82
+ signature: z.union([
83
+ z_SignatureEnvelope.Primitive,
84
+ z_SignatureEnvelope.Multisig,
85
+ ]),
86
+ type: z.union([z_SignatureEnvelope.Type, z.literal('multisig')]),
84
87
  witness: z.optional(z_Hex.Hex),
85
88
  }
86
89
 
87
- /** Decoded key authorization schema (TIP-1049 admin fields are paired: both or neither). */
88
- export const Domain = z.union([
89
- z.object({
90
+ /** Decoded key authorization schema. */
91
+ export const Domain = z
92
+ .object({
90
93
  ...domainShape,
91
- account: z_Address.Address,
92
- isAdmin: z.boolean(),
93
- }),
94
- z.object(domainShape),
95
- ])
94
+ account: z.optional(z_Address.Address),
95
+ isAdmin: z.optional(z.boolean()),
96
+ })
97
+ .check(
98
+ z.refine(
99
+ (value) => value.type !== 'multisig' || value.account != null,
100
+ 'multisig key grants require a parent account binding',
101
+ ),
102
+ )
96
103
 
97
104
  const domainToRpcShape = {
98
105
  ...domainShape,
@@ -102,14 +109,18 @@ const domainToRpcShape = {
102
109
  }
103
110
 
104
111
  /** Encode-only decoded key authorization schema accepting numberish `toRpc` inputs. */
105
- export const DomainToRpc = z.union([
106
- z.object({
112
+ export const DomainToRpc = z
113
+ .object({
107
114
  ...domainToRpcShape,
108
- account: z_Address.Address,
109
- isAdmin: z.boolean(),
110
- }),
111
- z.object(domainToRpcShape),
112
- ])
115
+ account: z.optional(z_Address.Address),
116
+ isAdmin: z.optional(z.boolean()),
117
+ })
118
+ .check(
119
+ z.refine(
120
+ (value) => value.type !== 'multisig' || value.account != null,
121
+ 'multisig key grants require a parent account binding',
122
+ ),
123
+ )
113
124
 
114
125
  /** Codec decoding an RPC key authorization into a signed key authorization. */
115
126
  export const KeyAuthorization = z.codec(Rpc, Domain, {
@@ -7,53 +7,17 @@ import * as z from 'zod/mini'
7
7
  import * as z_MultisigConfig from './MultisigConfig.js'
8
8
  import * as z_SignatureEnvelope from './SignatureEnvelope.js'
9
9
 
10
- const NestedPrimitiveApproval = z.object({
10
+ const PrimitiveApproval = z.strictObject({
11
11
  keyData: z.optional(z_Hex.Hex),
12
12
  keyType: z.optional(z_SignatureEnvelope.Type),
13
13
  owner: z_Address.Address,
14
14
  })
15
15
 
16
- const PrimitiveApproval = z.object({
17
- keyData: z.optional(z_Hex.Hex),
18
- keyType: z.optional(z_SignatureEnvelope.Type),
19
- owner: z_Address.Address,
20
- type: z.literal('primitive'),
21
- })
22
-
23
- const NestedSpec = z.object({
24
- account: z_Address.Address,
25
- approvals: z.readonly(
26
- z
27
- .array(NestedPrimitiveApproval)
28
- .check(z.maxLength(core_MultisigConfig.maxSignatures)),
29
- ),
30
- config: z_MultisigConfig.Config,
31
- })
32
-
33
- const NestedSpecRpc = z.object({
34
- account: z_Address.Address,
35
- approvals: z.readonly(
36
- z
37
- .array(NestedPrimitiveApproval)
38
- .check(z.maxLength(core_MultisigConfig.maxSignatures)),
39
- ),
40
- config: z_Hex.Hex,
41
- })
42
-
43
16
  /** Native multisig simulation spec schema. */
44
17
  export const Domain = z.object({
45
- account: z_Address.Address,
46
18
  approvals: z.readonly(
47
19
  z
48
- .array(
49
- z.union([
50
- PrimitiveApproval,
51
- z.object({
52
- spec: NestedSpec,
53
- type: z.literal('multisig'),
54
- }),
55
- ]),
56
- )
20
+ .array(PrimitiveApproval)
57
21
  .check(z.maxLength(core_MultisigConfig.maxSignatures)),
58
22
  ),
59
23
  config: z_MultisigConfig.Config,
@@ -61,18 +25,9 @@ export const Domain = z.object({
61
25
 
62
26
  const Rpc_ = z
63
27
  .object({
64
- account: z_Address.Address,
65
28
  approvals: z.readonly(
66
29
  z
67
- .array(
68
- z.union([
69
- PrimitiveApproval,
70
- z.object({
71
- spec: NestedSpecRpc,
72
- type: z.literal('multisig'),
73
- }),
74
- ]),
75
- )
30
+ .array(PrimitiveApproval)
76
31
  .check(z.maxLength(core_MultisigConfig.maxSignatures)),
77
32
  ),
78
33
  config: z_Hex.Hex,
@@ -72,23 +72,35 @@ export const WebAuthnRpc = z.object({
72
72
  export const PrimitiveRpc = z.union([Secp256k1Rpc, P256Rpc, WebAuthnRpc])
73
73
 
74
74
  /** RPC keychain signature envelope schema. */
75
- export const KeychainRpc = z.object({
76
- keyId: z.optional(z_Address.Address),
77
- // `signature` is recursive; type the getter concretely to break the cycle.
78
- signature: z.lazy(
79
- (): z.ZodMiniType<core_SignatureEnvelope.SignatureEnvelopeRpc> =>
80
- Rpc as never,
81
- ),
82
- type: z.literal('keychain'),
83
- userAddress: z_Address.Address,
84
- version: z.optional(KeychainVersion),
85
- })
75
+ export const KeychainRpc = z
76
+ .object({
77
+ keyId: z.optional(z_Address.Address),
78
+ // `signature` is recursive; type the getter concretely to break the cycle.
79
+ signature: z.lazy(
80
+ (): z.ZodMiniType<core_SignatureEnvelope.SignatureEnvelopeRpc> =>
81
+ Rpc as never,
82
+ ),
83
+ type: z.literal('keychain'),
84
+ userAddress: z_Address.Address,
85
+ version: z.optional(KeychainVersion),
86
+ })
87
+ .check(
88
+ z.refine((value) => {
89
+ try {
90
+ core_SignatureEnvelope.fromRpc(value)
91
+ return true
92
+ } catch {
93
+ return false
94
+ }
95
+ }, 'multisig access keys require keychain V2'),
96
+ )
86
97
 
87
98
  /** RPC native multisig signature envelope schema. */
88
99
  export const MultisigRpc = z_Hex.Hex.check(
89
100
  z.refine((value) => {
90
101
  try {
91
- return core_SignatureEnvelope.fromRpc(value).type === 'multisig'
102
+ core_SignatureEnvelope.fromRpc(value)
103
+ return true
92
104
  } catch {
93
105
  return false
94
106
  }
@@ -133,34 +145,34 @@ export const WebAuthn = z.object({
133
145
  export const Primitive = z.union([Secp256k1, P256, WebAuthn])
134
146
 
135
147
  /** Keychain signature envelope schema. */
136
- export const Keychain = z.object({
137
- // `inner` is recursive; type the getter concretely to break the cycle.
138
- inner: z.lazy(
139
- (): z.ZodMiniType<core_SignatureEnvelope.SignatureEnvelope> =>
140
- Domain as never,
141
- ),
142
- keyId: z.optional(z_Address.Address),
143
- type: z.literal('keychain'),
144
- userAddress: z_Address.Address,
145
- version: z.optional(KeychainVersion),
146
- })
148
+ export const Keychain = z
149
+ .object({
150
+ // `inner` is recursive; type the getter concretely to break the cycle.
151
+ inner: z.lazy(
152
+ (): z.ZodMiniType<core_SignatureEnvelope.SignatureEnvelope> =>
153
+ Domain as never,
154
+ ),
155
+ keyId: z.optional(z_Address.Address),
156
+ type: z.literal('keychain'),
157
+ userAddress: z_Address.Address,
158
+ version: z.optional(KeychainVersion),
159
+ })
160
+ .check(
161
+ z.refine(
162
+ (value) => core_SignatureEnvelope.validate(value),
163
+ 'multisig access keys require keychain V2',
164
+ ),
165
+ )
147
166
 
148
167
  /** Native multisig signature envelope schema. */
149
168
  export const Multisig = z
150
169
  .object({
151
170
  account: z_Address.Address,
152
171
  config: z_MultisigConfig.Config,
153
- // `signatures` is recursive; type the getter concretely to break the cycle.
154
- signatures: z.lazy(
155
- (): z.ZodMiniType<readonly core_SignatureEnvelope.SignatureEnvelope[]> =>
156
- z.readonly(
157
- z
158
- .array(Domain)
159
- .check(
160
- z.minLength(1),
161
- z.maxLength(core_MultisigConfig.maxSignatures),
162
- ),
163
- ) as never,
172
+ signatures: z.readonly(
173
+ z
174
+ .array(Primitive)
175
+ .check(z.minLength(1), z.maxLength(core_MultisigConfig.maxSignatures)),
164
176
  ),
165
177
  type: z.literal('multisig'),
166
178
  })
@@ -189,7 +201,6 @@ function fromRpc(
189
201
  value: core_SignatureEnvelope.SignatureEnvelopeRpc,
190
202
  ): core_SignatureEnvelope.SignatureEnvelope {
191
203
  if (typeof value === 'string') return core_SignatureEnvelope.fromRpc(value)
192
-
193
204
  if (value.type === 'secp256k1') {
194
205
  const secp256k1 = value as core_SignatureEnvelope.Secp256k1Rpc
195
206
  return {
@@ -23,6 +23,7 @@ const KeyType = z.union([
23
23
  z.literal('secp256k1'),
24
24
  z.literal('p256'),
25
25
  z.literal('webAuthn'),
26
+ z.literal('multisig'),
26
27
  ])
27
28
 
28
29
  const SignatureRpc = z.object({
@@ -83,6 +84,7 @@ export const Rpc = z.object({
83
84
  maxFeePerBlobGas: z.optional(z_Hex.Hex),
84
85
  maxFeePerGas: z.optional(z_Hex.Hex),
85
86
  maxPriorityFeePerGas: z.optional(z_Hex.Hex),
87
+ keyAuthorizationSimulation: z.optional(z_MultisigSimulation.Rpc),
86
88
  multisigSimulation: z.optional(z_MultisigSimulation.Rpc),
87
89
  nonce: z.optional(z_Hex.Hex),
88
90
  nonceKey: z.optional(z_Hex.Hex),
@@ -136,6 +138,7 @@ export const Domain = z.object({
136
138
  maxFeePerBlobGas: z.optional(z.bigint()),
137
139
  maxFeePerGas: z.optional(z.bigint()),
138
140
  maxPriorityFeePerGas: z.optional(z.bigint()),
141
+ keyAuthorizationSimulation: z.optional(z_MultisigSimulation.Domain),
139
142
  multisigSimulation: z.optional(z_MultisigSimulation.Domain),
140
143
  nonce: z.optional(z.bigint()),
141
144
  nonceKey: z.optional(z.union([z.bigint(), z.literal('random')])),
@@ -175,6 +178,7 @@ export const DomainToRpc = z.object({
175
178
  maxFeePerBlobGas: z.optional(uintBigintNumberish()),
176
179
  maxFeePerGas: z.optional(uintBigintNumberish()),
177
180
  maxPriorityFeePerGas: z.optional(uintBigintNumberish()),
181
+ keyAuthorizationSimulation: z.optional(z_MultisigSimulation.Domain),
178
182
  multisigSimulation: z.optional(z_MultisigSimulation.Domain),
179
183
  nonce: z.optional(uintBigintNumberish()),
180
184
  nonceKey: z.optional(z.union([uintBigintNumberish(), z.literal('random')])),
@@ -250,6 +254,11 @@ function fromRpc(
250
254
  if (typeof request.keyData !== 'undefined') request_.keyData = request.keyData
251
255
  if (typeof request.keyId !== 'undefined') request_.keyId = request.keyId
252
256
  if (typeof request.keyType !== 'undefined') request_.keyType = request.keyType
257
+ if (typeof request.keyAuthorizationSimulation !== 'undefined')
258
+ request_.keyAuthorizationSimulation = z.decode(
259
+ z_MultisigSimulation.MultisigSimulation,
260
+ request.keyAuthorizationSimulation,
261
+ )
253
262
  if (typeof request.multisigSimulation !== 'undefined')
254
263
  request_.multisigSimulation = z.decode(
255
264
  z_MultisigSimulation.MultisigSimulation,
@@ -338,6 +347,11 @@ function toRpc(
338
347
  if (typeof request.keyId !== 'undefined') request_rpc.keyId = request.keyId
339
348
  if (typeof request.keyType !== 'undefined')
340
349
  request_rpc.keyType = request.keyType
350
+ if (typeof request.keyAuthorizationSimulation !== 'undefined')
351
+ request_rpc.keyAuthorizationSimulation = z.encode(
352
+ z_MultisigSimulation.MultisigSimulation,
353
+ request.keyAuthorizationSimulation,
354
+ )
341
355
  if (typeof request.multisigSimulation !== 'undefined')
342
356
  request_rpc.multisigSimulation = z.encode(
343
357
  z_MultisigSimulation.MultisigSimulation,
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from 'vp/test'
2
+ import * as core_SignatureEnvelope from '../../../tempo/SignatureEnvelope.js'
2
3
  import * as core_KeyAuthorization from '../../../tempo/KeyAuthorization.js'
3
4
  import * as z_KeyAuthorization from '../KeyAuthorization.js'
4
5
  import * as z from 'zod/mini'
@@ -20,6 +21,35 @@ const rpc = {
20
21
  } as const
21
22
 
22
23
  describe('KeyAuthorization', () => {
24
+ test('rejects unbound multisig grants through every schema', () => {
25
+ const domain = {
26
+ ...z.decode(z_KeyAuthorization.KeyAuthorization, rpc),
27
+ type: 'multisig',
28
+ } as const
29
+ for (const account of [undefined, null])
30
+ expect(
31
+ z.safeDecode(z_KeyAuthorization.KeyAuthorization, {
32
+ ...rpc,
33
+ keyType: 'multisig',
34
+ account,
35
+ }).success,
36
+ ).toMatchInlineSnapshot(`false`)
37
+ for (const schema of [
38
+ z_KeyAuthorization.Domain,
39
+ z_KeyAuthorization.DomainToRpc,
40
+ ]) {
41
+ expect(z.safeParse(schema, domain).success).toMatchInlineSnapshot(`false`)
42
+ expect(
43
+ z.safeParse(schema, { ...domain, account: rpc.keyId }).success,
44
+ ).toMatchInlineSnapshot(`true`)
45
+ }
46
+ for (const codec of [
47
+ z_KeyAuthorization.KeyAuthorization,
48
+ z_KeyAuthorization.KeyAuthorizationToRpc,
49
+ ])
50
+ expect(z.safeEncode(codec, domain).success).toMatchInlineSnapshot(`false`)
51
+ })
52
+
23
53
  test('decodes an RPC key authorization', () => {
24
54
  expect(z.decode(z_KeyAuthorization.KeyAuthorization, rpc)).toEqual(
25
55
  core_KeyAuthorization.fromRpc(rpc),
@@ -141,27 +171,15 @@ describe('KeyAuthorization', () => {
141
171
  ).toBe(false)
142
172
  })
143
173
 
144
- test('round-trips multisig signatures', () => {
145
- const multisigRpc =
146
- '0xf89794be95c3f554e9fc85ec51be69a3d807a0d55bcf2cf83ba000000000000000000000000000000000000000000000000000000000000000000101d7d694f39fd6e51aad88f6f4ce6ab8827279cfffb9226601f843b841fa78c5905fb0b9d6066ef531f962a62bc6ef0d5eb59ecb134056d206f75aaed7780926ff2601a935c2c79707d9e1799948c9f19dcdde1e090e903b19a07923d01c' as const
147
- const withMultisig = { ...rpc, signature: multisigRpc }
148
- const decoded = z.decode(z_KeyAuthorization.KeyAuthorization, withMultisig)
149
- expect(decoded).toEqual(core_KeyAuthorization.fromRpc(withMultisig))
150
- expect(z.encode(z_KeyAuthorization.KeyAuthorization, decoded)).toEqual(
151
- core_KeyAuthorization.toRpc(decoded),
152
- )
153
- })
154
-
155
- test('rejects keychain signatures', () => {
156
- const keychainRpc = {
157
- signature: rpc.signature,
158
- type: 'keychain',
159
- userAddress: '0x1111111111111111111111111111111111111111',
174
+ test('rejects legacy multisig signatures', () => {
175
+ const multisigRpc = {
176
+ account: '0x1111111111111111111111111111111111111111',
177
+ signatures: [rpc.signature],
160
178
  } as const
161
179
  expect(
162
180
  z.safeDecode(z_KeyAuthorization.KeyAuthorization, {
163
181
  ...rpc,
164
- signature: keychainRpc,
182
+ signature: multisigRpc,
165
183
  } as never).success,
166
184
  ).toBe(false)
167
185
 
@@ -170,11 +188,42 @@ describe('KeyAuthorization', () => {
170
188
  z.safeEncode(z_KeyAuthorization.KeyAuthorization, {
171
189
  ...authorization,
172
190
  signature: {
173
- inner: authorization.signature,
174
- type: 'keychain',
175
- userAddress: keychainRpc.userAddress,
191
+ account: multisigRpc.account,
192
+ signatures: [authorization.signature],
193
+ type: 'multisig',
176
194
  },
177
195
  } as never).success,
178
196
  ).toBe(false)
179
197
  })
198
+ test('round-trips account-bound multisig grants', () => {
199
+ const signature = core_SignatureEnvelope.from({
200
+ account: '0x2222222222222222222222222222222222222222',
201
+ config: {
202
+ threshold: 1,
203
+ owners: [
204
+ { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
205
+ ],
206
+ },
207
+ signatures: [
208
+ core_SignatureEnvelope.fromRpc(
209
+ rpc.signature,
210
+ ) as core_SignatureEnvelope.Primitive,
211
+ ],
212
+ })
213
+ const signed = core_KeyAuthorization.from(
214
+ {
215
+ account: signature.account,
216
+ address: '0x3333333333333333333333333333333333333333',
217
+ chainId: 1n,
218
+ type: 'multisig',
219
+ },
220
+ { signature },
221
+ )
222
+ const encoded = z.encode(z_KeyAuthorization.KeyAuthorization, signed)
223
+ const decoded = z.decode(z_KeyAuthorization.KeyAuthorization, encoded)
224
+ expect(decoded).toEqual(
225
+ core_KeyAuthorization.fromRpc(core_KeyAuthorization.toRpc(signed)),
226
+ )
227
+ expect(decoded.account).toBe(signature.account)
228
+ })
180
229
  })
@@ -4,24 +4,11 @@ import * as z_MultisigSimulation from '../MultisigSimulation.js'
4
4
  import * as z from 'zod/mini'
5
5
 
6
6
  const rpc = {
7
- account: '0xcccccccccccccccccccccccccccccccccccccccc',
8
7
  approvals: [
9
8
  {
10
- owner: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
11
- type: 'primitive',
12
- },
13
- {
14
- spec: {
15
- account: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
16
- approvals: [
17
- {
18
- owner: '0xdddddddddddddddddddddddddddddddddddddddd',
19
- },
20
- ],
21
- config:
22
- '0xf83ba022222222222222222222222222222222222222222222222222222222222222220201d7d694dddddddddddddddddddddddddddddddddddddddd01',
23
- },
24
- type: 'multisig',
9
+ keyType: 'webAuthn',
10
+ keyData: '0x0005',
11
+ owner: '0x1111111111111111111111111111111111111111',
25
12
  },
26
13
  ],
27
14
  config:
@@ -46,24 +33,12 @@ describe('MultisigSimulation', () => {
46
33
  }).success,
47
34
  ).toMatchInlineSnapshot(`false`)
48
35
  })
49
-
50
- test('error: rejects more than eight nested approvals', () => {
36
+ test('error: rejects nested approvals', () => {
51
37
  expect(
52
38
  z.safeDecode(z_MultisigSimulation.Rpc, {
53
39
  ...rpc,
54
- approvals: [
55
- {
56
- ...rpc.approvals[1],
57
- spec: {
58
- ...rpc.approvals[1].spec,
59
- approvals: Array.from(
60
- { length: 9 },
61
- () => rpc.approvals[1].spec.approvals[0],
62
- ),
63
- },
64
- },
65
- ],
66
- }).success,
40
+ approvals: [{ type: 'multisig', spec: rpc }],
41
+ } as never).success,
67
42
  ).toMatchInlineSnapshot(`false`)
68
43
  })
69
44