@agoric/portfolio-api 0.1.1-dev-94f7dd3.0.94f7dd3 → 0.1.1-dev-0cd653b.0.0cd653b

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/portfolio-api",
3
- "version": "0.1.1-dev-94f7dd3.0.94f7dd3",
3
+ "version": "0.1.1-dev-0cd653b.0.0cd653b",
4
4
  "description": "API for Portfolio management",
5
5
  "repository": {
6
6
  "type": "git",
@@ -46,8 +46,8 @@
46
46
  "generate:ymax-machine": "npx tsx scripts/gen-ymax-machine.mts"
47
47
  },
48
48
  "dependencies": {
49
- "@agoric/internal": "0.3.3-dev-94f7dd3.0.94f7dd3",
50
- "@agoric/orchestration": "0.1.1-dev-94f7dd3.0.94f7dd3",
49
+ "@agoric/internal": "0.3.3-dev-0cd653b.0.0cd653b",
50
+ "@agoric/orchestration": "0.1.1-dev-0cd653b.0.0cd653b",
51
51
  "@endo/common": "^1.4.0",
52
52
  "@endo/errors": "^1.3.1",
53
53
  "@endo/patterns": "^1.9.1"
@@ -73,5 +73,5 @@
73
73
  "engines": {
74
74
  "node": "^22.11 || ^24.14"
75
75
  },
76
- "gitHead": "94f7dd333365233251880bd61ef8c803433ecf4d"
76
+ "gitHead": "0cd653b11224a7bf48e42d387532844b4c6e091f"
77
77
  }
@@ -9,9 +9,9 @@
9
9
  * Currently all types and helpers are built around a hard-coded Ymax product
10
10
  * name but with some effort this could be parametrizable
11
11
  */
12
- import type { Address, TypedDataDomain, TypedDataToPrimitiveTypes } from 'abitype';
12
+ import type { Address, TypedDataDomain } from 'abitype';
13
13
  import type { TypedDataDefinition } from 'viem';
14
- import type { TypedDataParameter } from '@agoric/orchestration/src/utils/abitype.js';
14
+ import type { TypedDataParameter, TypedDataToStructType } from '@agoric/orchestration/src/utils/abitype.js';
15
15
  import { type Witness, type getPermitWitnessTransferFromData, type getPermitBatchWitnessTransferFromData } from '@agoric/orchestration/src/utils/permit2.js';
16
16
  declare const YMAX_DOMAIN_NAME = "Ymax";
17
17
  declare const YMAX_DOMAIN_VERSION = "1";
@@ -52,10 +52,39 @@ declare const PortfolioStandaloneTypeParams: [{
52
52
  * The set of portfolio operations supported by EVM Wallets, and their associated params
53
53
  */
54
54
  declare const OperationTypes: {
55
+ /**
56
+ * Open a portfolio, optionally in the same signed message enabling
57
+ * auto-features and/or granting portfolio permissions to an automation
58
+ * agent's Agoric address, now that `features`/`grantee` can be marked
59
+ * `optional` in the EIP-712 type definition. This is the preferred,
60
+ * general form of the former separate {@link OpenPortfolioWithAutoFeatures}
61
+ * / {@link OpenPortfolioWithGrant} operations, which remain supported as
62
+ * distinct operation types for backward compatibility with existing
63
+ * clients/messages, but should not be needed for new callers. Granting
64
+ * delivers the delegation to `grantee.address`, exactly as a standalone
65
+ * {@link Grant} would; enabling auto-features behaves exactly as a
66
+ * standalone {@link SetAutoFeatures} would.
67
+ *
68
+ * - allocations: initial target allocation across instruments
69
+ * - features: auto-features to enable on open, if any
70
+ * - grantee: delegation recipient and encoded portfolio permissions, if any
71
+ */
55
72
  readonly OpenPortfolio: readonly [{
56
73
  readonly name: "allocations";
57
74
  readonly type: "Allocation[]";
75
+ }, {
76
+ readonly name: "features";
77
+ readonly type: "PortfolioAutoFeatures";
78
+ readonly optional: true;
79
+ }, {
80
+ readonly name: "grantee";
81
+ readonly type: "DelegationGrantee";
82
+ readonly optional: true;
58
83
  }];
84
+ /**
85
+ * @deprecated prefer {@link OpenPortfolio} with its optional `features`
86
+ * field. Kept as a distinct operation type for backward compatibility.
87
+ */
59
88
  readonly OpenPortfolioWithAutoFeatures: readonly [{
60
89
  readonly name: "allocations";
61
90
  readonly type: "Allocation[]";
@@ -64,18 +93,8 @@ declare const OperationTypes: {
64
93
  readonly type: "PortfolioAutoFeatures";
65
94
  }];
66
95
  /**
67
- * Open a portfolio and, in the same signed message, grant portfolio
68
- * permissions to an automation agent's Agoric address. This collapses the
69
- * former two-step "create portfolio" + "Grant" flow into a single user
70
- * signature: the contract creates the portfolio with the given allocations
71
- * and then delivers the delegation to `grantee.address`, exactly as a
72
- * standalone {@link Grant} would.
73
- *
74
- * Like {@link OpenPortfolio}, this is a permit2-wrapped (funds-bearing)
75
- * operation; the accompanying Permit2 supplies the initial deposit.
76
- *
77
- * - allocations: initial target allocation across instruments
78
- * - grantee: delegation recipient and encoded portfolio permissions
96
+ * @deprecated prefer {@link OpenPortfolio} with its optional `grantee`
97
+ * field. Kept as a distinct operation type for backward compatibility.
79
98
  */
80
99
  readonly OpenPortfolioWithGrant: readonly [{
81
100
  readonly name: "allocations";
@@ -164,6 +183,10 @@ declare const OperationSubTypes: {
164
183
  readonly PortfolioPermissions: readonly [{
165
184
  readonly name: "allocation";
166
185
  readonly type: "bool";
186
+ }, {
187
+ readonly name: "rebalance";
188
+ readonly type: "bool";
189
+ readonly optional: true;
167
190
  }];
168
191
  readonly DelegationGrantee: readonly [{
169
192
  readonly name: "address";
@@ -187,9 +210,9 @@ declare const OperationSubTypes: {
187
210
  * - [{instrument: 'A', portion: 60}, {instrument: 'B', portion: 40}] => 60:40 ratio
188
211
  * - [{instrument: 'A', portion: 6}, {instrument: 'B', portion: 4}] => 6:4 ratio (same as 60:40)
189
212
  */
190
- export type TargetAllocation = TypedDataToPrimitiveTypes<typeof OperationSubTypes>['Allocation'];
191
- export type PortfolioPermissionsEIP712 = TypedDataToPrimitiveTypes<typeof OperationSubTypes>['PortfolioPermissions'];
192
- export type PortfolioAutoFeaturesEIP712 = TypedDataToPrimitiveTypes<typeof OperationSubTypes>['PortfolioAutoFeatures'];
213
+ export type TargetAllocation = TypedDataToStructType<typeof OperationSubTypes, 'Allocation'>;
214
+ export type PortfolioPermissionsEIP712 = TypedDataToStructType<typeof OperationSubTypes, 'PortfolioPermissions'>;
215
+ export type PortfolioAutoFeaturesEIP712 = TypedDataToStructType<typeof OperationSubTypes, 'PortfolioAutoFeatures'>;
193
216
  /**
194
217
  * In the wrapped case, the domain is fixed by permit2, so we can't choose name/version there.
195
218
  * so we put the ymax-specifc domain name and version in the type name.
@@ -216,14 +239,43 @@ type YmaxStandaloneOperationTypes<T extends OperationTypeNames = OperationTypeNa
216
239
  type YmaxStandaloneTypes<T extends OperationTypeNames = OperationTypeNames> = YmaxStandaloneOperationTypes<T> & typeof OperationSubTypes & {
217
240
  EIP712Domain: typeof StandaloneDomainTypeParams;
218
241
  };
219
- export type YmaxOperationType<T extends OperationTypeNames> = TypedDataToPrimitiveTypes<OperationTypes & typeof OperationSubTypes>[T];
220
- type YmaxWitnessData<T extends OperationTypeNames> = TypedDataToPrimitiveTypes<YmaxWitnessTypes<T>>[YmaxWitnessTypeParam<T>['type']];
221
- type YmaxStandaloneData<T extends OperationTypeNames> = TypedDataToPrimitiveTypes<YmaxStandaloneTypes<T>>[T];
242
+ export type YmaxOperationType<T extends OperationTypeNames> = TypedDataToStructType<OperationTypes & typeof OperationSubTypes, T>;
243
+ type YmaxWitnessData<T extends OperationTypeNames> = TypedDataToStructType<YmaxWitnessTypes<T>, YmaxWitnessTypeParam<T>['type']>;
244
+ type YmaxStandaloneData<T extends OperationTypeNames> = TypedDataToStructType<YmaxStandaloneTypes<T>, T>;
222
245
  export declare const getYmaxOperationTypes: <T extends OperationTypeNames>(operation: T) => { [K in T]: {
246
+ /**
247
+ * Open a portfolio, optionally in the same signed message enabling
248
+ * auto-features and/or granting portfolio permissions to an automation
249
+ * agent's Agoric address, now that `features`/`grantee` can be marked
250
+ * `optional` in the EIP-712 type definition. This is the preferred,
251
+ * general form of the former separate {@link OpenPortfolioWithAutoFeatures}
252
+ * / {@link OpenPortfolioWithGrant} operations, which remain supported as
253
+ * distinct operation types for backward compatibility with existing
254
+ * clients/messages, but should not be needed for new callers. Granting
255
+ * delivers the delegation to `grantee.address`, exactly as a standalone
256
+ * {@link Grant} would; enabling auto-features behaves exactly as a
257
+ * standalone {@link SetAutoFeatures} would.
258
+ *
259
+ * - allocations: initial target allocation across instruments
260
+ * - features: auto-features to enable on open, if any
261
+ * - grantee: delegation recipient and encoded portfolio permissions, if any
262
+ */
223
263
  readonly OpenPortfolio: readonly [{
224
264
  readonly name: "allocations";
225
265
  readonly type: "Allocation[]";
266
+ }, {
267
+ readonly name: "features";
268
+ readonly type: "PortfolioAutoFeatures";
269
+ readonly optional: true;
270
+ }, {
271
+ readonly name: "grantee";
272
+ readonly type: "DelegationGrantee";
273
+ readonly optional: true;
226
274
  }];
275
+ /**
276
+ * @deprecated prefer {@link OpenPortfolio} with its optional `features`
277
+ * field. Kept as a distinct operation type for backward compatibility.
278
+ */
227
279
  readonly OpenPortfolioWithAutoFeatures: readonly [{
228
280
  readonly name: "allocations";
229
281
  readonly type: "Allocation[]";
@@ -232,18 +284,8 @@ export declare const getYmaxOperationTypes: <T extends OperationTypeNames>(opera
232
284
  readonly type: "PortfolioAutoFeatures";
233
285
  }];
234
286
  /**
235
- * Open a portfolio and, in the same signed message, grant portfolio
236
- * permissions to an automation agent's Agoric address. This collapses the
237
- * former two-step "create portfolio" + "Grant" flow into a single user
238
- * signature: the contract creates the portfolio with the given allocations
239
- * and then delivers the delegation to `grantee.address`, exactly as a
240
- * standalone {@link Grant} would.
241
- *
242
- * Like {@link OpenPortfolio}, this is a permit2-wrapped (funds-bearing)
243
- * operation; the accompanying Permit2 supplies the initial deposit.
244
- *
245
- * - allocations: initial target allocation across instruments
246
- * - grantee: delegation recipient and encoded portfolio permissions
287
+ * @deprecated prefer {@link OpenPortfolio} with its optional `grantee`
288
+ * field. Kept as a distinct operation type for backward compatibility.
247
289
  */
248
290
  readonly OpenPortfolioWithGrant: readonly [{
249
291
  readonly name: "allocations";
@@ -329,6 +371,10 @@ export declare const getYmaxOperationTypes: <T extends OperationTypeNames>(opera
329
371
  readonly PortfolioPermissions: readonly [{
330
372
  readonly name: "allocation";
331
373
  readonly type: "bool";
374
+ }, {
375
+ readonly name: "rebalance";
376
+ readonly type: "bool";
377
+ readonly optional: true;
332
378
  }];
333
379
  readonly DelegationGrantee: readonly [{
334
380
  readonly name: "address";
@@ -1 +1 @@
1
- {"version":3,"file":"eip712-messages.d.ts","sourceRoot":"","sources":["eip712-messages.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"eip712-messages.d.ts","sourceRoot":"","sources":["eip712-messages.ts"],"names":[],"mappings":"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"}
@@ -10,14 +10,12 @@
10
10
  * name but with some effort this could be parametrizable
11
11
  */
12
12
 
13
-
14
-
15
-
16
-
17
-
18
-
13
+
19
14
 
20
-
15
+
16
+
17
+
18
+
21
19
  import {
22
20
 
23
21
 
@@ -26,6 +24,7 @@ import {
26
24
  TokenPermissionsComponents,
27
25
  } from '@agoric/orchestration/src/utils/permit2.js';
28
26
  import { sameEvmAddress } from '@agoric/orchestration/src/utils/address.js';
27
+ import { normalizeAndValidateEIP712Data } from '@agoric/orchestration/src/utils/viem-utils/eip712-normalize.js';
29
28
 
30
29
  const YMAX_DOMAIN_NAME = 'Ymax';
31
30
  const YMAX_DOMAIN_VERSION = '1';
@@ -70,24 +69,39 @@ const PortfolioStandaloneTypeParams = [
70
69
  * The set of portfolio operations supported by EVM Wallets, and their associated params
71
70
  */
72
71
  const OperationTypes = {
73
- OpenPortfolio: [{ name: 'allocations', type: 'Allocation[]' }],
72
+ /**
73
+ * Open a portfolio, optionally in the same signed message enabling
74
+ * auto-features and/or granting portfolio permissions to an automation
75
+ * agent's Agoric address, now that `features`/`grantee` can be marked
76
+ * `optional` in the EIP-712 type definition. This is the preferred,
77
+ * general form of the former separate {@link OpenPortfolioWithAutoFeatures}
78
+ * / {@link OpenPortfolioWithGrant} operations, which remain supported as
79
+ * distinct operation types for backward compatibility with existing
80
+ * clients/messages, but should not be needed for new callers. Granting
81
+ * delivers the delegation to `grantee.address`, exactly as a standalone
82
+ * {@link Grant} would; enabling auto-features behaves exactly as a
83
+ * standalone {@link SetAutoFeatures} would.
84
+ *
85
+ * - allocations: initial target allocation across instruments
86
+ * - features: auto-features to enable on open, if any
87
+ * - grantee: delegation recipient and encoded portfolio permissions, if any
88
+ */
89
+ OpenPortfolio: [
90
+ { name: 'allocations', type: 'Allocation[]' },
91
+ { name: 'features', type: 'PortfolioAutoFeatures', optional: true },
92
+ { name: 'grantee', type: 'DelegationGrantee', optional: true },
93
+ ],
94
+ /**
95
+ * @deprecated prefer {@link OpenPortfolio} with its optional `features`
96
+ * field. Kept as a distinct operation type for backward compatibility.
97
+ */
74
98
  OpenPortfolioWithAutoFeatures: [
75
99
  { name: 'allocations', type: 'Allocation[]' },
76
100
  { name: 'features', type: 'PortfolioAutoFeatures' },
77
101
  ],
78
102
  /**
79
- * Open a portfolio and, in the same signed message, grant portfolio
80
- * permissions to an automation agent's Agoric address. This collapses the
81
- * former two-step "create portfolio" + "Grant" flow into a single user
82
- * signature: the contract creates the portfolio with the given allocations
83
- * and then delivers the delegation to `grantee.address`, exactly as a
84
- * standalone {@link Grant} would.
85
- *
86
- * Like {@link OpenPortfolio}, this is a permit2-wrapped (funds-bearing)
87
- * operation; the accompanying Permit2 supplies the initial deposit.
88
- *
89
- * - allocations: initial target allocation across instruments
90
- * - grantee: delegation recipient and encoded portfolio permissions
103
+ * @deprecated prefer {@link OpenPortfolio} with its optional `grantee`
104
+ * field. Kept as a distinct operation type for backward compatibility.
91
105
  */
92
106
  OpenPortfolioWithGrant: [
93
107
  { name: 'allocations', type: 'Allocation[]' },
@@ -128,7 +142,15 @@ const OperationTypes = {
128
142
  { name: 'features', type: 'PortfolioAutoFeatures' },
129
143
  PortfolioIdParam,
130
144
  ],
131
- } ;
145
+ // `satisfies Record<string, readonly TypedDataParameter[]>` rather than
146
+ // abitype's own `TypedData` (whose `TypedDataParameter` is strictly
147
+ // `{name, type}`) so struct fields here can carry the repo-local `optional`
148
+ // marker without tripping excess-property checks on this literal. Downstream
149
+ // consumption (e.g. `satisfies TypedData` on values derived from `typeof
150
+ // OperationTypes`) is unaffected: those check a type reference structurally,
151
+ // and an extra optional `optional?` property doesn't break assignability to
152
+ // abitype's `TypedData`.
153
+ } ;
132
154
  ;
133
155
  ;
134
156
 
@@ -139,14 +161,17 @@ const OperationSubTypes = {
139
161
  ],
140
162
  Asset: TokenPermissionsComponents,
141
163
  /** @see {@link PortfolioPermissions} */
142
- PortfolioPermissions: [{ name: 'allocation', type: 'bool' }],
164
+ PortfolioPermissions: [
165
+ { name: 'allocation', type: 'bool' },
166
+ { name: 'rebalance', type: 'bool', optional: true },
167
+ ],
143
168
  DelegationGrantee: [
144
169
  { name: 'address', type: 'string' },
145
170
  { name: 'permissions', type: 'PortfolioPermissions' },
146
171
  ],
147
172
  /** @see {@link PortfolioAutoFeatures} */
148
173
  PortfolioAutoFeatures: [{ name: 'rebalance', type: 'bool' }],
149
- } ;
174
+ } ;
150
175
 
151
176
  /**
152
177
  * Target allocation for portfolio positions.
@@ -157,9 +182,10 @@ const OperationSubTypes = {
157
182
  * - [{instrument: 'A', portion: 60}, {instrument: 'B', portion: 40}] => 60:40 ratio
158
183
  * - [{instrument: 'A', portion: 6}, {instrument: 'B', portion: 4}] => 6:4 ratio (same as 60:40)
159
184
  */
160
- ;
161
-
162
-
185
+ ;
186
+
187
+
188
+
163
189
  ;
164
190
 
165
191
 
@@ -167,13 +193,15 @@ const OperationSubTypes = {
167
193
 
168
194
 
169
195
 
170
- ;
171
-
172
-
196
+ ;
197
+
198
+
199
+
173
200
 
174
- ;
175
-
201
+ ;
176
202
 
203
+
204
+
177
205
 
178
206
  /**
179
207
  * In the wrapped case, the domain is fixed by permit2, so we can't choose name/version there.
@@ -234,13 +262,16 @@ const getYmaxWitnessTypeParam = (
234
262
 
235
263
 
236
264
  ;
237
-
265
+
238
266
 
239
- ;
240
-
241
-
242
- ;
243
-
267
+ ;
268
+
269
+
270
+
271
+ ;
272
+
273
+
274
+
244
275
 
245
276
  const getYmaxOperationAndSubTypes = (
246
277
 
@@ -280,12 +311,24 @@ export const getYmaxOperationTypes = (
280
311
  export const getYmaxWitness = (
281
312
  operation ,
282
313
  data ,
283
- ) =>
284
- makeWitness (
285
- data,
286
- getYmaxWitnessTypes(operation),
287
- getYmaxWitnessTypeParam(operation),
314
+ ) => {
315
+ const witnessTypeParam = getYmaxWitnessTypeParam(operation);
316
+ // Normalize away unused `optional` fields (and their now-unreferenced
317
+ // types) so that e.g. omitting `grantee`/`features` on `OpenPortfolio`
318
+ // produces a `types`/`message` pair that real EIP-712 hashing can encode.
319
+ // This is the authoring side, not adversarial input, so extra fields are
320
+ // dropped rather than rejected.
321
+ const { message, types } = normalizeAndValidateEIP712Data({
322
+ message: data ,
323
+ types: getYmaxWitnessTypes(operation),
324
+ primaryType: witnessTypeParam.type,
325
+ });
326
+ return makeWitness (
327
+ message ,
328
+ types ,
329
+ witnessTypeParam,
288
330
  );
331
+ };
289
332
 
290
333
  export const getYmaxStandaloneDomain = (
291
334
  chainId ,
@@ -304,13 +347,22 @@ export const getYmaxStandaloneOperationData = (
304
347
 
305
348
 
306
349
  ) => {
307
- const types = getYmaxStandaloneTypes(operation);
350
+ // Normalize away unused `optional` fields (and their now-unreferenced
351
+ // types) so that e.g. omitting unchanged `features` on `SetAutoFeatures`
352
+ // produces a `types`/`message` pair that real EIP-712 hashing can encode.
353
+ // This is the authoring side, not adversarial input, so extra fields are
354
+ // dropped rather than rejected.
355
+ const { message, types } = normalizeAndValidateEIP712Data({
356
+ message: data ,
357
+ types: getYmaxStandaloneTypes(operation),
358
+ primaryType: operation,
359
+ });
308
360
 
309
361
  return {
310
362
  domain: getYmaxStandaloneDomain(chainId, verifyingContract),
311
363
  types,
312
364
  primaryType: operation,
313
- message: data ,
365
+ message: message ,
314
366
  }
315
367
 
316
368
  ;
@@ -359,36 +411,38 @@ export function validateYmaxDomain(
359
411
 
360
412
  ,
361
413
  ) {
362
- const baseDomain = domain;
363
- validateYmaxDomainBase(baseDomain);
414
+ // Destructure before narrowing `domain` below, so `chainId`/`verifyingContract`
415
+ // remain accessible as independent bindings afterward.
416
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
417
+ const { name, version, chainId, verifyingContract, ...extra } = domain;
418
+ validateYmaxDomainBase(domain);
364
419
 
365
- if (
366
- typeof domain.chainId !== 'bigint' ||
367
- domain.verifyingContract === undefined
368
- ) {
420
+ if (typeof chainId !== 'bigint' || verifyingContract === undefined) {
369
421
  throw new Error(`Ymax domain must include chain ID and verifying contract`);
370
422
  }
371
423
 
372
424
  if (validContractAddresses) {
373
- const chainIdStr = String(domain.chainId);
425
+ const chainIdStr = String(chainId);
374
426
 
375
427
  if (!(chainIdStr in validContractAddresses)) {
376
- throw new Error(`Unknown chain ID in Ymax domain: ${domain.chainId}`);
428
+ throw new Error(`Unknown chain ID in Ymax domain: ${chainId}`);
377
429
  }
378
430
 
379
431
  if (
380
- !sameEvmAddress(
381
- domain.verifyingContract,
382
- validContractAddresses[chainIdStr],
383
- )
432
+ !sameEvmAddress(verifyingContract, validContractAddresses[chainIdStr])
384
433
  ) {
385
434
  throw new Error(
386
- `Invalid verifying contract for chain ID ${domain.chainId}: ${domain.verifyingContract} (expected ${validContractAddresses[chainIdStr]})`,
435
+ `Invalid verifying contract for chain ID ${chainId}: ${verifyingContract} (expected ${validContractAddresses[chainIdStr]})`,
387
436
  );
388
437
  }
389
438
  }
390
439
 
391
- // XXX: check no extra fields?
440
+ const extraKeys = Object.keys(extra);
441
+ if (extraKeys.length) {
442
+ throw new Error(
443
+ `Unexpected field(s) in Ymax domain: ${extraKeys.join(', ')}`,
444
+ );
445
+ }
392
446
  }
393
447
 
394
448
  export function validateYmaxOperationTypeName (
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { AbiParameterToPrimitiveType, Address } from 'abitype';
9
9
  import type { getTypesForEIP712Domain } from 'viem';
10
- import type { hashStruct, isHex, recoverTypedDataAddress, validateTypedData } from 'viem/utils';
10
+ import type { hashStruct, isHex, recoverTypedDataAddress } from 'viem/utils';
11
11
  import type { encodeType, WithSignature } from '@agoric/orchestration/src/utils/viem.js';
12
12
  import { type Permit2Domain, type PermitWitnessTransferFromInputComponents } from '@agoric/orchestration/src/utils/permit2.js';
13
13
  import { type OperationTypeNames, type YmaxStandaloneOperationData, type YmaxPermitWitnessTransferFromData, type YmaxOperationType, type YmaxFullDomain } from './eip712-messages.js';
@@ -44,7 +44,6 @@ export declare const makeEVMHandlerUtils: (viemUtils: {
44
44
  isHex: typeof isHex;
45
45
  hashStruct: typeof hashStruct;
46
46
  recoverTypedDataAddress: typeof recoverTypedDataAddress;
47
- validateTypedData: typeof validateTypedData;
48
47
  encodeType: typeof encodeType;
49
48
  getTypesForEIP712Domain: typeof getTypesForEIP712Domain;
50
49
  }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"message-handler-helpers.d.ts","sourceRoot":"","sources":["message-handler-helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"message-handler-helpers.d.ts","sourceRoot":"","sources":["message-handler-helpers.ts"],"names":[],"mappings":"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"}
@@ -14,8 +14,8 @@
14
14
 
15
15
 
16
16
 
17
-
18
17
  import { sameEvmAddress } from '@agoric/orchestration/src/utils/address.js';
18
+ import { normalizeAndValidateEIP712Data } from '@agoric/orchestration/src/utils/viem-utils/eip712-normalize.js';
19
19
  ;
20
20
 
21
21
 
@@ -82,7 +82,6 @@ export const makeEVMHandlerUtils = (viemUtils
82
82
 
83
83
 
84
84
 
85
-
86
85
 
87
86
 
88
87
  ) => {
@@ -90,21 +89,19 @@ export const makeEVMHandlerUtils = (viemUtils
90
89
  isHex,
91
90
  hashStruct,
92
91
  recoverTypedDataAddress,
93
- validateTypedData,
94
92
  encodeType,
95
93
  getTypesForEIP712Domain,
96
94
  } = viemUtils;
97
95
 
98
- for (const util of [
96
+ for (const [utilName, util] of Object.entries({
99
97
  isHex,
100
98
  hashStruct,
101
99
  recoverTypedDataAddress,
102
- validateTypedData,
103
100
  encodeType,
104
101
  getTypesForEIP712Domain,
105
- ]) {
102
+ })) {
106
103
  if (typeof util !== 'function') {
107
- throw new Error(`Expected viemUtils.${util} to be a function`);
104
+ throw new Error(`Expected viemUtils.${utilName} to be a function`);
108
105
  }
109
106
  }
110
107
 
@@ -114,10 +111,19 @@ export const makeEVMHandlerUtils = (viemUtils
114
111
 
115
112
  /**
116
113
  * Extract operation type name and data from an EIP-712 standalone Ymax typed data.
117
- * Validates that the message data satisfies the expected types for the operation,
118
- * but does not validate that the supplied data types exactly match the expected
119
- * types. In particular the message data may be a superset of the expected types,
120
- * and extra fields are included in the returned extracted details.
114
+ *
115
+ * By the time this is called, `data.message` has already been through the
116
+ * "reject anything unsigned" normalize pass (see
117
+ * `extractOperationDetailsFromDataWithAddress`), so any field here was
118
+ * actually part of what was signed. This function normalizes *and
119
+ * validates* it a second time against the types this (possibly older)
120
+ * version of the code expects for the operation: any field the signer's
121
+ * client signed but this version doesn't know about is dropped (not
122
+ * rejected -- it was signed, just not supported yet), and any `optional`
123
+ * field is resolved based on whether it's actually present in the
124
+ * message. The returned `data` is exactly the normalized/expected shape,
125
+ * never a superset of it, and is guaranteed to satisfy the expected types
126
+ * (required fields present, values of the right shape/range).
121
127
  *
122
128
  * Assumes the domain has the expected shape of a Ymax domain.
123
129
  *
@@ -145,24 +151,40 @@ export const makeEVMHandlerUtils = (viemUtils
145
151
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
146
152
  const { nonce, deadline, ..._operationData } =
147
153
  standaloneData.message ;
148
- const operationData = _operationData ;
154
+ const operationData = _operationData ;
149
155
  const operation = standaloneData.primaryType;
150
- // @ts-expect-error inference issue
151
- validateTypedData({
152
- types: getYmaxOperationTypes(operation),
153
- message: operationData,
154
- primaryType: operation,
155
- });
156
- return { operation, domain, data: operationData };
156
+ const { message: normalizedData } = normalizeAndValidateEIP712Data(
157
+ {
158
+ message: operationData ,
159
+ types: getYmaxOperationTypes(operation),
160
+ primaryType: operation,
161
+ },
162
+ { onExtraField: 'drop' },
163
+ );
164
+ return {
165
+ operation,
166
+ domain,
167
+ data: normalizedData ,
168
+ };
157
169
  };
158
170
 
159
171
  /**
160
172
  * Extract operation type name and data from an EIP-712 Permit2 witness typed data.
161
173
  * Validates that the supplied types exactly match types of a permit2 message.
162
- * Validates that the witness data satisfies the expected types for the operation,
163
- * but does not validate that the supplied data types exactly match the expected
164
- * types. In particular the witness data may be a superset of the expected types,
165
- * and extra fields are included in the returned witness data.
174
+ *
175
+ * By the time this is called, `data.message`/`data.types` have already been
176
+ * through the "reject anything unsigned" normalize pass (see
177
+ * `extractOperationDetailsFromDataWithAddress`), so any field in the
178
+ * witness data here was actually part of what was signed. This function
179
+ * normalizes *and validates* it a second time against the types this
180
+ * (possibly older) version of the code expects for the operation: any
181
+ * field the signer's client signed but this version doesn't know about is
182
+ * dropped (not rejected -- it was signed, just not supported yet), and
183
+ * any `optional` field is resolved based on whether it's actually present
184
+ * in the witness data. The returned `data` is exactly the
185
+ * normalized/expected shape, never a superset of it, and is guaranteed to
186
+ * satisfy the expected types (required fields present, values of the
187
+ * right shape/range).
166
188
  *
167
189
  * Assumes the message has already been validated against the types from the data.
168
190
  * Assumes the domain has the expected shape of a permit2 domain.
@@ -183,23 +205,24 @@ export const makeEVMHandlerUtils = (viemUtils
183
205
  const witnessField = extractWitnessFieldFromTypes(permitData.types);
184
206
  const witnessData = permitData.message[
185
207
  witnessField.name
186
- ] ;
208
+ ] ;
187
209
  const { primaryType, domain } = splitWitnessFieldType(witnessField.type);
188
210
  const chainId = BigInt(data.domain.chainId);
189
211
  const operation = primaryType ;
190
212
 
191
- // Validates the witness data satisfies the expected types for the operation
192
- // @ts-expect-error inference issue
193
- validateTypedData({
194
- types: getYmaxOperationTypes(operation),
195
- message: witnessData,
196
- primaryType: operation,
197
- });
213
+ const { message: normalizedWitnessData } = normalizeAndValidateEIP712Data(
214
+ {
215
+ message: witnessData ,
216
+ types: getYmaxOperationTypes(operation),
217
+ primaryType: operation,
218
+ },
219
+ { onExtraField: 'drop' },
220
+ );
198
221
  const spender = permitData.message.spender;
199
222
  return {
200
223
  operation,
201
224
  domain: { ...domain, chainId, verifyingContract: spender },
202
- data: witnessData,
225
+ data: normalizedWitnessData ,
203
226
  };
204
227
  };
205
228
 
@@ -306,6 +329,23 @@ export const makeEVMHandlerUtils = (viemUtils
306
329
  * Validates the domain of the typed data, and optionally the verifying
307
330
  * contract and spender against the provided contract addresses.
308
331
  *
332
+ * Before anything else, the message is normalized *and validated* against
333
+ * its own (untrusted) wire-supplied `types`, rejecting any field not
334
+ * declared there: such a field was never part of the signed struct, so it
335
+ * never affected the EIP-712 hash and could have been added after signing
336
+ * without invalidating the signature. This is the AGO-874 defense. The
337
+ * same function also validates that the message actually satisfies those
338
+ * wire-supplied types (required fields present, values in range/shape),
339
+ * recursing correctly through arrays -- something real EIP-712 tooling
340
+ * (e.g. viem's `validateTypedData`) does not do. The domain is validated
341
+ * the same way, separately (its values live outside `message`).
342
+ * A *different*, later normalize pass (in
343
+ * `extractOperationDetailsFromStandaloneData` /
344
+ * `extractOperationDetailsFromPermit2WitnessData`) drops -- rather than
345
+ * rejects -- fields that were genuinely signed but aren't supported by
346
+ * this version's generated operation types; those are legitimate,
347
+ * merely unsupported (yet), not a security concern.
348
+ *
309
349
  * @param data The operation data with an `address` field of the signing owner.
310
350
  * @param contractAddresses Optionally, a set of valid contract addresses to validate against
311
351
  * @param contractAddresses.permit2 If provided, validates a permit2 based message's verifying contract
@@ -331,24 +371,42 @@ export const makeEVMHandlerUtils = (viemUtils
331
371
 
332
372
 
333
373
  ;
334
- const { nonce, deadline } = otherData.message;
335
374
 
336
375
  if (!domain) {
337
376
  throw new Error(`Missing domain in typed data`);
338
377
  }
339
- validateTypedData({
378
+
379
+ // Reject anything not part of the actual signed structure (see doc above).
380
+ const { message: signedMessage, types: signedTypes } =
381
+ normalizeAndValidateEIP712Data(
382
+ {
383
+ message: otherData.message ,
384
+ types: otherData.types,
385
+ primaryType: otherData.primaryType,
386
+ },
387
+ { onExtraField: 'throw' },
388
+ );
389
+ const signedData = {
340
390
  ...otherData,
341
- // @ts-expect-error inference issue
342
- domain,
343
- types: {
344
- ...otherData.types,
345
- // Do not trust the type definitions coming from the message for the domain
346
- EIP712Domain: getTypesForEIP712Domain({ domain }),
347
- },
391
+ message: signedMessage,
392
+ types: signedTypes,
393
+ };
394
+ const { nonce, deadline } =
395
+ signedMessage ;
396
+
397
+ // Do not trust type definitions coming from the message for the domain;
398
+ // derive them from `domain`'s own shape instead, then validate `domain`
399
+ // against that (e.g. `chainId` range, `verifyingContract` shape).
400
+ // Domain-specific checks (name/version/contract match) happen later, in
401
+ // `validateYmaxDomain`/`validatePermit2Domain`.
402
+ normalizeAndValidateEIP712Data({
403
+ message: domain ,
404
+ types: { EIP712Domain: getTypesForEIP712Domain({ domain }) },
405
+ primaryType: 'EIP712Domain',
348
406
  });
349
407
 
350
408
  if (isPermit2MessageType(data.primaryType)) {
351
- const { signature, ...permit2Data } = otherData
409
+ const { signature, ...permit2Data } = signedData
352
410
 
353
411
 
354
412
  ;
@@ -383,7 +441,7 @@ export const makeEVMHandlerUtils = (viemUtils
383
441
  deadline,
384
442
  };
385
443
  } else {
386
- const standaloneData = otherData
444
+ const standaloneData = signedData
387
445
 
388
446
 
389
447
  ;
@@ -1 +1 @@
1
- {"version":3,"file":"portfolio-permissions.d.ts","sourceRoot":"","sources":["portfolio-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EACV,2BAA2B,EAC3B,0BAA0B,EAC3B,MAAM,iCAAiC,CAAC;AAEzC;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,oBAAoB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;AAE7E;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,YAAY,CAAC,oBAAoB,CACG,CAAC;AAE7E,eAAO,MAAM,+BAA+B,EAAE,YAAY,CAAC,0BAA0B,CACzC,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,EAAE,YAAY,CAAC,uBAAuB,CAC9C,CAAC;AAElC,kEAAkE;AAClE,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,EAAE,YAAY,CAAC,qBAAqB,CACxB,CAAC;AAEpD,eAAO,MAAM,gCAAgC,EAAE,YAAY,CAAC,2BAA2B,CAC5C,CAAC;AAE5C,uEAAuE;AACvE,MAAM,MAAM,wBAAwB,GAAG,qBAAqB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;AAE/E,mEAAmE;AACnE,eAAO,MAAM,6BAA6B,EAAE,YAAY,CAAC,wBAAwB,CAChD,CAAC"}
1
+ {"version":3,"file":"portfolio-permissions.d.ts","sourceRoot":"","sources":["portfolio-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EACV,2BAA2B,EAC3B,0BAA0B,EAC3B,MAAM,iCAAiC,CAAC;AAEzC;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,oBAAoB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;AAE7E;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,YAAY,CAAC,oBAAoB,CACG,CAAC;AAE7E,eAAO,MAAM,+BAA+B,EAAE,YAAY,CAAC,0BAA0B,CACT,CAAC;AAE7E;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,EAAE,YAAY,CAAC,uBAAuB,CAC9C,CAAC;AAElC,kEAAkE;AAClE,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,EAAE,YAAY,CAAC,qBAAqB,CACxB,CAAC;AAEpD,eAAO,MAAM,gCAAgC,EAAE,YAAY,CAAC,2BAA2B,CAC5C,CAAC;AAE5C,uEAAuE;AACvE,MAAM,MAAM,wBAAwB,GAAG,qBAAqB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;AAE/E,mEAAmE;AACnE,eAAO,MAAM,6BAA6B,EAAE,YAAY,CAAC,wBAAwB,CAChD,CAAC"}
@@ -34,7 +34,7 @@ export const PortfolioPermissionsShape =
34
34
  M.splitRecord({}, { allocation: M.boolean(), rebalance: M.boolean() }, {});
35
35
 
36
36
  export const PortfolioPermissionsEIP712Shape =
37
- M.splitRecord({ allocation: M.boolean() });
37
+ M.splitRecord({ allocation: M.boolean() }, { rebalance: M.boolean() }, {});
38
38
 
39
39
  /**
40
40
  * Extensible app-level shape for portfolio permissions.