@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 +4 -4
- package/src/evm-wallet/eip712-messages.d.ts +78 -32
- package/src/evm-wallet/eip712-messages.d.ts.map +1 -1
- package/src/evm-wallet/eip712-messages.js +112 -58
- package/src/evm-wallet/message-handler-helpers.d.ts +1 -2
- package/src/evm-wallet/message-handler-helpers.d.ts.map +1 -1
- package/src/evm-wallet/message-handler-helpers.js +101 -43
- package/src/portfolio-permissions.d.ts.map +1 -1
- package/src/portfolio-permissions.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/portfolio-api",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
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-
|
|
50
|
-
"@agoric/orchestration": "0.1.1-dev-
|
|
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": "
|
|
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
|
|
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
|
-
*
|
|
68
|
-
*
|
|
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 =
|
|
191
|
-
export type PortfolioPermissionsEIP712 =
|
|
192
|
-
export type PortfolioAutoFeaturesEIP712 =
|
|
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> =
|
|
220
|
-
type YmaxWitnessData<T extends OperationTypeNames> =
|
|
221
|
-
type YmaxStandaloneData<T extends OperationTypeNames> =
|
|
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
|
-
*
|
|
236
|
-
*
|
|
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":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,
|
|
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
|
-
|
|
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
|
-
*
|
|
80
|
-
*
|
|
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: [
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
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:
|
|
365
|
+
message: message ,
|
|
314
366
|
}
|
|
315
367
|
|
|
316
368
|
;
|
|
@@ -359,36 +411,38 @@ export function validateYmaxDomain(
|
|
|
359
411
|
|
|
360
412
|
,
|
|
361
413
|
) {
|
|
362
|
-
|
|
363
|
-
|
|
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(
|
|
425
|
+
const chainIdStr = String(chainId);
|
|
374
426
|
|
|
375
427
|
if (!(chainIdStr in validContractAddresses)) {
|
|
376
|
-
throw new Error(`Unknown chain ID in Ymax domain: ${
|
|
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 ${
|
|
435
|
+
`Invalid verifying contract for chain ID ${chainId}: ${verifyingContract} (expected ${validContractAddresses[chainIdStr]})`,
|
|
387
436
|
);
|
|
388
437
|
}
|
|
389
438
|
}
|
|
390
439
|
|
|
391
|
-
|
|
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
|
|
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":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EACV,UAAU,EACV,KAAK,EACL,uBAAuB,
|
|
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.${
|
|
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
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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 } =
|
|
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 =
|
|
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,
|
|
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.
|