@agoric/portfolio-api 0.1.1-dev-d57b08e.0.d57b08e → 0.1.1-dev-2ae3f1f.0.2ae3f1f

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-d57b08e.0.d57b08e",
3
+ "version": "0.1.1-dev-2ae3f1f.0.2ae3f1f",
4
4
  "description": "API for Portfolio management",
5
5
  "type": "module",
6
6
  "files": [
@@ -27,11 +27,11 @@
27
27
  "generate:ymax-machine": "npx tsx scripts/gen-ymax-machine.mts"
28
28
  },
29
29
  "dependencies": {
30
- "@agoric/orchestration": "0.1.1-dev-d57b08e.0.d57b08e",
30
+ "@agoric/orchestration": "0.1.1-dev-2ae3f1f.0.2ae3f1f",
31
31
  "@endo/common": "^1.2.13"
32
32
  },
33
33
  "devDependencies": {
34
- "@agoric/internal": "0.3.3-dev-d57b08e.0.d57b08e",
34
+ "@agoric/internal": "0.3.3-dev-2ae3f1f.0.2ae3f1f",
35
35
  "@types/js-yaml": "^4",
36
36
  "ajv": "^6.12.6",
37
37
  "ava": "^5.3.0",
@@ -64,5 +64,5 @@
64
64
  "engines": {
65
65
  "node": "^20.9 || ^22.11"
66
66
  },
67
- "gitHead": "d57b08e6945269499ff15845f664405099f0f39b"
67
+ "gitHead": "2ae3f1fb1423324b633432fe7149a26bcaadd843"
68
68
  }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @file Portfolio operations are either in a permit2 witness or standalone,
3
+ * in either case, following EIP-712
4
+ *
5
+ * The fields included in the operation differ based on which way they're submitted.
6
+ * In the wrapped case, we don't want to repeat stuff from the permit envelope.
7
+ * {@link OperationTypes}
8
+ *
9
+ * Currently all types and helpers are built around a hard-coded Ymax product
10
+ * name but with some effort this could be parametrizable
11
+ */
12
+ import type { TypedDataDomain, TypedDataToPrimitiveTypes } from 'abitype';
13
+ import type { TypedDataDefinition } from 'viem';
14
+ import type { TypedDataParameter } from '@agoric/orchestration/src/utils/abitype.ts';
15
+ import { type Witness, type getPermitWitnessTransferFromData, type getPermitBatchWitnessTransferFromData } from '@agoric/orchestration/src/utils/permit2.ts';
16
+ declare const YMAX_DOMAIN_NAME = "Ymax";
17
+ declare const YMAX_DOMAIN_VERSION = "1";
18
+ declare const StandaloneDomainTypeParams: [{
19
+ readonly name: "name";
20
+ readonly type: "string";
21
+ }, {
22
+ readonly name: "version";
23
+ readonly type: "string";
24
+ }];
25
+ declare const YmaxStandaloneDomain: {
26
+ readonly name: "Ymax";
27
+ readonly version: "1";
28
+ };
29
+ declare const SharedPortfolioTypeParams: [];
30
+ /**
31
+ * Fields included in Permit data that we don't want duplicated in witness data,
32
+ * so only included in standalone typed data.
33
+ */
34
+ declare const PortfolioStandaloneTypeParams: [{
35
+ readonly name: "nonce";
36
+ readonly type: "uint256";
37
+ }, {
38
+ readonly name: "deadline";
39
+ readonly type: "uint256";
40
+ }];
41
+ /**
42
+ * The set of portfolio operations supported by EVM Wallets, and their associated params
43
+ */
44
+ declare const OperationTypes: {
45
+ readonly OpenPortfolio: readonly [{
46
+ readonly name: "allocations";
47
+ readonly type: "Allocation[]";
48
+ }];
49
+ readonly Rebalance: readonly [{
50
+ readonly name: "allocations";
51
+ readonly type: "Allocation[]";
52
+ }, {
53
+ readonly name: "portfolio";
54
+ readonly type: "uint256";
55
+ }];
56
+ readonly Deposit: readonly [{
57
+ readonly name: "portfolio";
58
+ readonly type: "uint256";
59
+ }];
60
+ };
61
+ type OperationTypes = typeof OperationTypes;
62
+ export type OperationTypeNames = keyof OperationTypes;
63
+ declare const OperationSubTypes: {
64
+ readonly Allocation: readonly [{
65
+ readonly name: "instrument";
66
+ readonly type: "string";
67
+ }, {
68
+ readonly name: "portion";
69
+ readonly type: "uint256";
70
+ }];
71
+ };
72
+ /**
73
+ * Target allocation for portfolio positions.
74
+ * Uses 'portion' (not 'basisPoints') to allow flexible ratios.
75
+ * The denominator is implicitly the sum of all portions.
76
+ *
77
+ * Examples:
78
+ * - [{instrument: 'A', portion: 60}, {instrument: 'B', portion: 40}] => 60:40 ratio
79
+ * - [{instrument: 'A', portion: 6}, {instrument: 'B', portion: 4}] => 6:4 ratio (same as 60:40)
80
+ */
81
+ export type TargetAllocation = TypedDataToPrimitiveTypes<typeof OperationSubTypes>['Allocation'];
82
+ /**
83
+ * In the wrapped case, the domain is fixed by permit2, so we can't choose name/version there.
84
+ * so we put the ymax-specifc domain name and version in the type name.
85
+ */
86
+ declare const getYmaxWitnessTypeName: <T extends OperationTypeNames>(operation: T) => `YmaxV1${T}`;
87
+ type YmaxWitnessTypeName<T extends OperationTypeNames> = ReturnType<typeof getYmaxWitnessTypeName<T>>;
88
+ declare const getYmaxWitnessFieldName: <T extends OperationTypeNames>(operation: T) => `ymax${T}`;
89
+ type YmaxWitnessFieldName<T extends OperationTypeNames> = ReturnType<typeof getYmaxWitnessFieldName<T>>;
90
+ export type YmaxWitnessTypeParam<T extends OperationTypeNames = OperationTypeNames> = TypedDataParameter<YmaxWitnessFieldName<T>, YmaxWitnessTypeName<T>>;
91
+ type YmaxWitnessOperationTypes<T extends OperationTypeNames = OperationTypeNames> = {
92
+ [K in T as YmaxWitnessTypeName<K>]: [
93
+ ...OperationTypes[K],
94
+ ...typeof SharedPortfolioTypeParams
95
+ ];
96
+ };
97
+ type YmaxWitnessTypes<T extends OperationTypeNames = OperationTypeNames> = YmaxWitnessOperationTypes<T> & typeof OperationSubTypes;
98
+ type YmaxStandaloneOperationTypes<T extends OperationTypeNames = OperationTypeNames> = {
99
+ [K in T]: [
100
+ ...OperationTypes[K],
101
+ ...typeof SharedPortfolioTypeParams,
102
+ ...typeof PortfolioStandaloneTypeParams
103
+ ];
104
+ };
105
+ type YmaxStandaloneTypes<T extends OperationTypeNames = OperationTypeNames> = YmaxStandaloneOperationTypes<T> & typeof OperationSubTypes & {
106
+ EIP712Domain: typeof StandaloneDomainTypeParams;
107
+ };
108
+ export type YmaxOperationType<T extends OperationTypeNames> = TypedDataToPrimitiveTypes<OperationTypes & typeof OperationSubTypes>[T];
109
+ type YmaxWitnessMappedTypeParam<T extends OperationTypeNames> = TypedDataParameter<YmaxWitnessFieldName<T>, Extract<keyof YmaxWitnessOperationTypes<T>, string>>;
110
+ export declare const getYmaxOperationTypes: <T extends OperationTypeNames>(operation: T) => { [K in T]: {
111
+ readonly OpenPortfolio: readonly [{
112
+ readonly name: "allocations";
113
+ readonly type: "Allocation[]";
114
+ }];
115
+ readonly Rebalance: readonly [{
116
+ readonly name: "allocations";
117
+ readonly type: "Allocation[]";
118
+ }, {
119
+ readonly name: "portfolio";
120
+ readonly type: "uint256";
121
+ }];
122
+ readonly Deposit: readonly [{
123
+ readonly name: "portfolio";
124
+ readonly type: "uint256";
125
+ }];
126
+ }[K]; } & {
127
+ readonly Allocation: readonly [{
128
+ readonly name: "instrument";
129
+ readonly type: "string";
130
+ }, {
131
+ readonly name: "portion";
132
+ readonly type: "uint256";
133
+ }];
134
+ };
135
+ export declare const getYmaxWitness: <T extends OperationTypeNames>(operation: T, data: NoInfer<TypedDataToPrimitiveTypes<YmaxWitnessTypes>[YmaxWitnessTypeName<T>]>) => Witness<YmaxWitnessTypes<T>, YmaxWitnessMappedTypeParam<T>>;
136
+ export declare const getYmaxStandaloneOperationData: <T extends OperationTypeNames>(data: NoInfer<TypedDataToPrimitiveTypes<YmaxStandaloneTypes>[T]>, operation: T) => TypedDataDefinition<YmaxStandaloneTypes<T>, T, T> & {
137
+ domain: typeof YmaxStandaloneDomain;
138
+ };
139
+ export type YmaxStandaloneOperationData<T extends OperationTypeNames = OperationTypeNames> = ReturnType<typeof getYmaxStandaloneOperationData<T>>;
140
+ export type YmaxPermitWitnessTransferFromData<T extends OperationTypeNames = OperationTypeNames> = ReturnType<typeof getPermitWitnessTransferFromData<YmaxWitnessTypes<T>, YmaxWitnessMappedTypeParam<T>>>;
141
+ export type YmaxPermitBatchWitnessTransferFromData<T extends OperationTypeNames = OperationTypeNames> = ReturnType<typeof getPermitBatchWitnessTransferFromData<YmaxWitnessTypes<T>, YmaxWitnessMappedTypeParam<T>>>;
142
+ export declare function validateYmaxDomain(domain: TypedDataDomain): asserts domain is typeof YmaxStandaloneDomain;
143
+ export declare function validateYmaxOperationTypeName<T extends OperationTypeNames>(typeName: string): asserts typeName is T;
144
+ export declare const splitWitnessFieldType: <T extends OperationTypeNames>(fieldName: `${typeof YMAX_DOMAIN_NAME}V${typeof YMAX_DOMAIN_VERSION}${T}`) => {
145
+ domain: {
146
+ readonly name: "Ymax";
147
+ readonly version: "1";
148
+ };
149
+ primaryType: T;
150
+ };
151
+ export {};
152
+ //# sourceMappingURL=eip712-messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eip712-messages.d.ts","sourceRoot":"","sources":["eip712-messages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,286 @@
1
+ /**
2
+ * @file Portfolio operations are either in a permit2 witness or standalone,
3
+ * in either case, following EIP-712
4
+ *
5
+ * The fields included in the operation differ based on which way they're submitted.
6
+ * In the wrapped case, we don't want to repeat stuff from the permit envelope.
7
+ * {@link OperationTypes}
8
+ *
9
+ * Currently all types and helpers are built around a hard-coded Ymax product
10
+ * name but with some effort this could be parametrizable
11
+ */
12
+
13
+ import type {
14
+ TypedData,
15
+ TypedDataDomain,
16
+ TypedDataToPrimitiveTypes,
17
+ } from 'abitype';
18
+ import type { TypedDataDefinition } from 'viem';
19
+ import type { TypedDataParameter } from '@agoric/orchestration/src/utils/abitype.ts';
20
+ import {
21
+ type Witness,
22
+ type getPermitWitnessTransferFromData,
23
+ type getPermitBatchWitnessTransferFromData,
24
+ makeWitness,
25
+ } from '@agoric/orchestration/src/utils/permit2.ts';
26
+
27
+ const YMAX_DOMAIN_NAME = 'Ymax';
28
+ const YMAX_DOMAIN_VERSION = '1';
29
+
30
+ const YMAX_WITNESS_FIELD_NAME_PREFIX = 'ymax';
31
+
32
+ const StandaloneDomainTypeParams = [
33
+ { name: 'name', type: 'string' },
34
+ { name: 'version', type: 'string' },
35
+ ] as const satisfies TypedDataParameter[];
36
+
37
+ const YmaxStandaloneDomain = {
38
+ name: YMAX_DOMAIN_NAME,
39
+ version: YMAX_DOMAIN_VERSION,
40
+ } as const satisfies TypedDataDomain;
41
+
42
+ // A param to designate the portfolio in operations by its `portfolioId`
43
+ const PortfolioIdParam = {
44
+ name: 'portfolio',
45
+ type: 'uint256',
46
+ } as const satisfies TypedDataParameter;
47
+
48
+ // XXX: Remove
49
+ const SharedPortfolioTypeParams = [] as const satisfies TypedDataParameter[];
50
+
51
+ /**
52
+ * Fields included in Permit data that we don't want duplicated in witness data,
53
+ * so only included in standalone typed data.
54
+ */
55
+ const PortfolioStandaloneTypeParams = [
56
+ { name: 'nonce', type: 'uint256' },
57
+ { name: 'deadline', type: 'uint256' },
58
+ ] as const satisfies TypedDataParameter[];
59
+
60
+ /**
61
+ * The set of portfolio operations supported by EVM Wallets, and their associated params
62
+ */
63
+ const OperationTypes = {
64
+ OpenPortfolio: [{ name: 'allocations', type: 'Allocation[]' }],
65
+ Rebalance: [{ name: 'allocations', type: 'Allocation[]' }, PortfolioIdParam],
66
+ Deposit: [PortfolioIdParam],
67
+ } as const satisfies TypedData;
68
+ type OperationTypes = typeof OperationTypes;
69
+ export type OperationTypeNames = keyof OperationTypes;
70
+
71
+ const OperationSubTypes = {
72
+ Allocation: [
73
+ { name: 'instrument', type: 'string' },
74
+ { name: 'portion', type: 'uint256' },
75
+ ],
76
+ } as const satisfies TypedData;
77
+
78
+ /**
79
+ * Target allocation for portfolio positions.
80
+ * Uses 'portion' (not 'basisPoints') to allow flexible ratios.
81
+ * The denominator is implicitly the sum of all portions.
82
+ *
83
+ * Examples:
84
+ * - [{instrument: 'A', portion: 60}, {instrument: 'B', portion: 40}] => 60:40 ratio
85
+ * - [{instrument: 'A', portion: 6}, {instrument: 'B', portion: 4}] => 6:4 ratio (same as 60:40)
86
+ */
87
+ export type TargetAllocation = TypedDataToPrimitiveTypes<
88
+ typeof OperationSubTypes
89
+ >['Allocation'];
90
+
91
+ /**
92
+ * In the wrapped case, the domain is fixed by permit2, so we can't choose name/version there.
93
+ * so we put the ymax-specifc domain name and version in the type name.
94
+ */
95
+ const getYmaxWitnessTypeName = <T extends OperationTypeNames>(operation: T) =>
96
+ `${YMAX_DOMAIN_NAME}V${YMAX_DOMAIN_VERSION}${operation}` as const;
97
+ type YmaxWitnessTypeName<T extends OperationTypeNames> = ReturnType<
98
+ typeof getYmaxWitnessTypeName<T>
99
+ >;
100
+ const getYmaxWitnessFieldName = <T extends OperationTypeNames>(operation: T) =>
101
+ `${YMAX_WITNESS_FIELD_NAME_PREFIX}${operation}` as const;
102
+ type YmaxWitnessFieldName<T extends OperationTypeNames> = ReturnType<
103
+ typeof getYmaxWitnessFieldName<T>
104
+ >;
105
+
106
+ /**
107
+ * showing a field named "witness" in the wallet signing UI is... boring
108
+ * so let's put something more relevant like the @{link OperationTypes}: Deposit etc.
109
+ */
110
+ const getYmaxWitnessTypeParam = <T extends OperationTypeNames>(
111
+ operation: T,
112
+ ): YmaxWitnessTypeParam<T> => ({
113
+ name: getYmaxWitnessFieldName(operation),
114
+ type: getYmaxWitnessTypeName(operation),
115
+ });
116
+ export type YmaxWitnessTypeParam<
117
+ T extends OperationTypeNames = OperationTypeNames,
118
+ > = TypedDataParameter<YmaxWitnessFieldName<T>, YmaxWitnessTypeName<T>>;
119
+
120
+ // TODO: Filter operation types to only those needed for witness/standalone
121
+ type YmaxWitnessOperationTypes<
122
+ T extends OperationTypeNames = OperationTypeNames,
123
+ > = {
124
+ [K in T as YmaxWitnessTypeName<K>]: [
125
+ ...OperationTypes[K],
126
+ ...typeof SharedPortfolioTypeParams,
127
+ ];
128
+ };
129
+ type YmaxWitnessTypes<T extends OperationTypeNames = OperationTypeNames> =
130
+ YmaxWitnessOperationTypes<T> & typeof OperationSubTypes;
131
+ type YmaxStandaloneOperationTypes<
132
+ T extends OperationTypeNames = OperationTypeNames,
133
+ > = {
134
+ [K in T]: [
135
+ ...OperationTypes[K],
136
+ ...typeof SharedPortfolioTypeParams,
137
+ ...typeof PortfolioStandaloneTypeParams,
138
+ ];
139
+ };
140
+ type YmaxStandaloneTypes<T extends OperationTypeNames = OperationTypeNames> =
141
+ YmaxStandaloneOperationTypes<T> &
142
+ typeof OperationSubTypes & {
143
+ EIP712Domain: typeof StandaloneDomainTypeParams;
144
+ };
145
+
146
+ export type YmaxOperationType<T extends OperationTypeNames> =
147
+ TypedDataToPrimitiveTypes<OperationTypes & typeof OperationSubTypes>[T];
148
+
149
+ // Hack to satisfy TypeScript limitations with generic inference in complex types
150
+ // Equivalent to `YmaxWitnessTypeParam`
151
+ type YmaxWitnessMappedTypeParam<T extends OperationTypeNames> =
152
+ TypedDataParameter<
153
+ YmaxWitnessFieldName<T>,
154
+ Extract<keyof YmaxWitnessOperationTypes<T>, string>
155
+ >;
156
+
157
+ const getYmaxWitnessTypes = <T extends OperationTypeNames>(operation: T) =>
158
+ ({
159
+ [getYmaxWitnessTypeName(operation)]: [
160
+ ...OperationTypes[operation],
161
+ ...SharedPortfolioTypeParams,
162
+ ],
163
+ ...OperationSubTypes,
164
+ }) as YmaxWitnessTypes<T> satisfies TypedData;
165
+
166
+ const getYmaxStandaloneTypes = <T extends OperationTypeNames>(operation: T) =>
167
+ ({
168
+ EIP712Domain: StandaloneDomainTypeParams,
169
+ [operation]: [
170
+ ...OperationTypes[operation],
171
+ ...SharedPortfolioTypeParams,
172
+ ...PortfolioStandaloneTypeParams,
173
+ ],
174
+ ...OperationSubTypes,
175
+ }) as YmaxStandaloneTypes<T> satisfies TypedData;
176
+
177
+ export const getYmaxOperationTypes = <T extends OperationTypeNames>(
178
+ operation: T,
179
+ ) =>
180
+ ({
181
+ [operation]: OperationTypes[operation],
182
+ ...OperationSubTypes,
183
+ }) as {
184
+ [K in T]: OperationTypes[K];
185
+ } & typeof OperationSubTypes satisfies TypedData;
186
+
187
+ export const getYmaxWitness = <T extends OperationTypeNames>(
188
+ operation: T,
189
+ data: NoInfer<
190
+ TypedDataToPrimitiveTypes<YmaxWitnessTypes>[YmaxWitnessTypeName<T>]
191
+ >,
192
+ ): Witness<YmaxWitnessTypes<T>, YmaxWitnessMappedTypeParam<T>> =>
193
+ // @ts-expect-error some generic inference issue I suppose?
194
+ makeWitness(
195
+ // @ts-expect-error some generic inference issue I suppose?
196
+ data,
197
+ getYmaxWitnessTypes(operation),
198
+ getYmaxWitnessTypeParam(operation),
199
+ );
200
+
201
+ export const getYmaxStandaloneOperationData = <T extends OperationTypeNames>(
202
+ data: NoInfer<TypedDataToPrimitiveTypes<YmaxStandaloneTypes>[T]>,
203
+ operation: T,
204
+ ): TypedDataDefinition<YmaxStandaloneTypes<T>, T, T> & {
205
+ domain: typeof YmaxStandaloneDomain;
206
+ } => {
207
+ const types = getYmaxStandaloneTypes(operation);
208
+
209
+ // @ts-expect-error some generic inference issue I suppose?
210
+ return {
211
+ domain: YmaxStandaloneDomain,
212
+ types,
213
+ primaryType: operation,
214
+ message: data,
215
+ };
216
+ };
217
+
218
+ export type YmaxStandaloneOperationData<
219
+ T extends OperationTypeNames = OperationTypeNames,
220
+ > = ReturnType<typeof getYmaxStandaloneOperationData<T>>;
221
+
222
+ export type YmaxPermitWitnessTransferFromData<
223
+ T extends OperationTypeNames = OperationTypeNames,
224
+ > = ReturnType<
225
+ typeof getPermitWitnessTransferFromData<
226
+ YmaxWitnessTypes<T>,
227
+ YmaxWitnessMappedTypeParam<T>
228
+ >
229
+ >;
230
+
231
+ export type YmaxPermitBatchWitnessTransferFromData<
232
+ T extends OperationTypeNames = OperationTypeNames,
233
+ > = ReturnType<
234
+ typeof getPermitBatchWitnessTransferFromData<
235
+ YmaxWitnessTypes<T>,
236
+ YmaxWitnessMappedTypeParam<T>
237
+ >
238
+ >;
239
+
240
+ export function validateYmaxDomain(
241
+ domain: TypedDataDomain,
242
+ ): asserts domain is typeof YmaxStandaloneDomain {
243
+ if (domain.name !== YMAX_DOMAIN_NAME) {
244
+ throw new Error(
245
+ `Invalid Ymax domain name: ${domain.name} (expected ${YMAX_DOMAIN_NAME})`,
246
+ );
247
+ }
248
+ if (domain.version !== YMAX_DOMAIN_VERSION) {
249
+ throw new Error(
250
+ `Invalid Ymax domain version: ${domain.version} (expected ${YMAX_DOMAIN_VERSION})`,
251
+ );
252
+ }
253
+ // XXX: check no extra fields?
254
+ }
255
+
256
+ export function validateYmaxOperationTypeName<T extends OperationTypeNames>(
257
+ typeName: string,
258
+ ): asserts typeName is T {
259
+ if (!(typeName in OperationTypes)) {
260
+ throw new Error(
261
+ `Unknown Ymax operation type: ${typeName} (expected one of ${Object.keys(OperationTypes).join(', ')})`,
262
+ );
263
+ }
264
+ }
265
+
266
+ export const splitWitnessFieldType = <T extends OperationTypeNames>(
267
+ fieldName: `${typeof YMAX_DOMAIN_NAME}V${typeof YMAX_DOMAIN_VERSION}${T}`,
268
+ ) => {
269
+ const match = fieldName.match(/^YmaxV(\d+)(\w+)$/u);
270
+ if (!match) {
271
+ throw new Error(`Invalid witness field type name: ${fieldName}`);
272
+ }
273
+ const [, version, operation] = match;
274
+ const domain = {
275
+ name: YMAX_DOMAIN_NAME,
276
+ version,
277
+ } satisfies TypedDataDomain;
278
+
279
+ validateYmaxDomain(domain);
280
+ validateYmaxOperationTypeName<T>(operation);
281
+
282
+ return {
283
+ domain,
284
+ primaryType: operation,
285
+ };
286
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @file Helpers to handle portfolio EIP-712 messages, extracting operation and
3
+ * deposit permit details, as well as verifying the signature.
4
+ *
5
+ * The viem runtime dependency is expected as a power to make this usable both
6
+ * on chain and in off-chain services.
7
+ */
8
+ import type { Address, TypedDataDomain } from 'abitype';
9
+ import type { Hex } from 'viem';
10
+ import type { hashStruct, recoverTypedDataAddress, validateTypedData } from 'viem/utils';
11
+ import { encodeType, type WithSignature } from '@agoric/orchestration/src/utils/viem.ts';
12
+ import { type PermitTransferFrom } from '@agoric/orchestration/src/utils/permit2.ts';
13
+ import { type OperationTypeNames, type YmaxStandaloneOperationData, type YmaxPermitWitnessTransferFromData, type YmaxOperationType } from './eip712-messages.ts';
14
+ export type YmaxOperationDetails<T extends OperationTypeNames> = {
15
+ [P in T]: {
16
+ operation: P;
17
+ data: YmaxOperationType<P>;
18
+ };
19
+ }[T];
20
+ export type PermitDataPayload = {
21
+ chainId: NonNullable<TypedDataDomain['chainId']>;
22
+ permit: PermitTransferFrom;
23
+ witness: Hex;
24
+ witnessTypeString: string;
25
+ };
26
+ export type FullMessageDetails<T extends OperationTypeNames = OperationTypeNames> = YmaxOperationDetails<T> & {
27
+ permit?: WithSignature<PermitDataPayload>;
28
+ evmWalletAddress: Address;
29
+ nonce: bigint;
30
+ deadline: bigint;
31
+ };
32
+ export declare const makeEVMHandlerUtils: (powers: {
33
+ hashStruct: typeof hashStruct;
34
+ recoverTypedDataAddress: typeof recoverTypedDataAddress;
35
+ validateTypedData: typeof validateTypedData;
36
+ encodeType: typeof encodeType;
37
+ }) => {
38
+ extractOperationDetailsFromStandaloneData: <T extends OperationTypeNames>(data: YmaxStandaloneOperationData<T>) => YmaxOperationDetails<T>;
39
+ extractOperationDetailsFromPermit2WitnessData: <T extends OperationTypeNames>(data: YmaxPermitWitnessTransferFromData<T>) => YmaxOperationDetails<T>;
40
+ extractPermitData: <T extends OperationTypeNames>(data: YmaxPermitWitnessTransferFromData<T>) => PermitDataPayload;
41
+ extractOperationDetailsFromSignedData: <T extends OperationTypeNames = "Deposit" | "Rebalance" | "OpenPortfolio">(signedData: WithSignature<YmaxPermitWitnessTransferFromData<T> | YmaxStandaloneOperationData<T>>) => Promise<FullMessageDetails<T>>;
42
+ };
43
+ //# sourceMappingURL=message-handler-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-handler-helpers.d.ts","sourceRoot":"","sources":["message-handler-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,KAAK,EACV,UAAU,EACV,uBAAuB,EAEvB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,UAAU,EACV,KAAK,aAAa,EACnB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,iCAAiC,EACtC,KAAK,iBAAiB,EAKvB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,kBAAkB,IAAI;KAC9D,CAAC,IAAI,CAAC,GAAG;QACR,SAAS,EAAE,CAAC,CAAC;QACb,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;KAC5B;CACF,CAAC,CAAC,CAAC,CAAC;AAEL,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC;IACjD,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,GAAG,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAC5B,CAAC,SAAS,kBAAkB,GAAG,kBAAkB,IAC/C,oBAAoB,CAAC,CAAC,CAAC,GAAG;IAC5B,MAAM,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAC1C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,QAAQ;IAC1C,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,UAAU,EAAE,OAAO,UAAU,CAAC;CAC/B;gDAUG,CAAC,SAAS,kBAAkB,QAEtB,2BAA2B,CAAC,CAAC,CAAC,KACnC,oBAAoB,CAAC,CAAC,CAAC;oDA2BxB,CAAC,SAAS,kBAAkB,QAEtB,iCAAiC,CAAC,CAAC,CAAC,KACzC,oBAAoB,CAAC,CAAC,CAAC;wBAwBC,CAAC,SAAS,kBAAkB,QAC/C,iCAAiC,CAAC,CAAC,CAAC,KACzC,iBAAiB;4CAkClB,CAAC,SAAS,kBAAkB,0DAEhB,aAAa,CACvB,iCAAiC,CAAC,CAAC,CAAC,GAAG,2BAA2B,CAAC,CAAC,CAAC,CACtE,KACA,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;CAiDlC,CAAC"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @file Helpers to handle portfolio EIP-712 messages, extracting operation and
3
+ * deposit permit details, as well as verifying the signature.
4
+ *
5
+ * The viem runtime dependency is expected as a power to make this usable both
6
+ * on chain and in off-chain services.
7
+ */
8
+
9
+ import type { Address, TypedDataDomain } from 'abitype';
10
+ import type { Hex } from 'viem';
11
+ import type {
12
+ hashStruct,
13
+ recoverTypedDataAddress,
14
+ RecoverTypedDataAddressParameters,
15
+ validateTypedData,
16
+ } from 'viem/utils';
17
+ import {
18
+ encodeType,
19
+ type WithSignature,
20
+ } from '@agoric/orchestration/src/utils/viem.ts';
21
+ import {
22
+ extractWitnessFieldFromTypes,
23
+ isPermit2MessageType,
24
+ makeWitnessTypeStringExtractor,
25
+ type PermitTransferFrom,
26
+ } from '@agoric/orchestration/src/utils/permit2.ts';
27
+ import {
28
+ type OperationTypeNames,
29
+ type YmaxStandaloneOperationData,
30
+ type YmaxPermitWitnessTransferFromData,
31
+ type YmaxOperationType,
32
+ splitWitnessFieldType,
33
+ validateYmaxDomain,
34
+ validateYmaxOperationTypeName,
35
+ getYmaxOperationTypes,
36
+ } from './eip712-messages.ts';
37
+
38
+ export type YmaxOperationDetails<T extends OperationTypeNames> = {
39
+ [P in T]: {
40
+ operation: P;
41
+ data: YmaxOperationType<P>;
42
+ };
43
+ }[T];
44
+
45
+ export type PermitDataPayload = {
46
+ chainId: NonNullable<TypedDataDomain['chainId']>;
47
+ permit: PermitTransferFrom;
48
+ witness: Hex;
49
+ witnessTypeString: string;
50
+ };
51
+
52
+ export type FullMessageDetails<
53
+ T extends OperationTypeNames = OperationTypeNames,
54
+ > = YmaxOperationDetails<T> & {
55
+ permit?: WithSignature<PermitDataPayload>;
56
+ evmWalletAddress: Address;
57
+ nonce: bigint;
58
+ deadline: bigint;
59
+ };
60
+
61
+ export const makeEVMHandlerUtils = (powers: {
62
+ hashStruct: typeof hashStruct;
63
+ recoverTypedDataAddress: typeof recoverTypedDataAddress;
64
+ validateTypedData: typeof validateTypedData;
65
+ encodeType: typeof encodeType;
66
+ }) => {
67
+ const { hashStruct, recoverTypedDataAddress, validateTypedData, encodeType } =
68
+ powers;
69
+ /**
70
+ * Extract operation type name and data from an EIP-712 standalone Ymax typed data
71
+ *
72
+ * @param data - The EIP-712 typed data of a standalone message
73
+ * @returns The operation type name and associated data
74
+ */
75
+ const extractOperationDetailsFromStandaloneData = <
76
+ T extends OperationTypeNames,
77
+ >(
78
+ data: YmaxStandaloneOperationData<T>,
79
+ ): YmaxOperationDetails<T> => {
80
+ // @ts-expect-error generic/union type compatibility
81
+ const standaloneData: YmaxStandaloneOperationData = data;
82
+
83
+ validateYmaxDomain(standaloneData.domain);
84
+ validateYmaxOperationTypeName<T>(standaloneData.primaryType);
85
+
86
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
87
+ const { nonce, deadline, ..._operationData } = standaloneData.message;
88
+ const operationData = _operationData as YmaxOperationType<T>;
89
+ const operation = standaloneData.primaryType;
90
+ // @ts-expect-error inference issue
91
+ validateTypedData({
92
+ types: getYmaxOperationTypes(operation),
93
+ message: operationData,
94
+ primaryType: operation,
95
+ });
96
+ return { operation, data: operationData };
97
+ };
98
+
99
+ /**
100
+ * Extract operation type name and data from an EIP-712 Permit2 witness typed data.
101
+ *
102
+ * @param data - The EIP-712 typed data of a Permit2 witness message
103
+ * @returns The operation type name and associated data
104
+ */
105
+ const extractOperationDetailsFromPermit2WitnessData = <
106
+ T extends OperationTypeNames,
107
+ >(
108
+ data: YmaxPermitWitnessTransferFromData<T>,
109
+ ): YmaxOperationDetails<T> => {
110
+ // @ts-expect-error generic/union type compatibility
111
+ const permitData: YmaxPermitWitnessTransferFromData = data;
112
+
113
+ const witnessField = extractWitnessFieldFromTypes(permitData.types);
114
+ const witnessData = permitData.message[
115
+ witnessField.name
116
+ ] as YmaxOperationType<T>;
117
+ const operation = splitWitnessFieldType(witnessField.type).primaryType as T;
118
+ // @ts-expect-error inference issue
119
+ validateTypedData({
120
+ types: getYmaxOperationTypes(operation),
121
+ message: witnessData,
122
+ primaryType: operation,
123
+ });
124
+ return { operation, data: witnessData };
125
+ };
126
+
127
+ /**
128
+ * Extract the data that can be used as partial arguments to permit2's
129
+ * permitWitnessTransferFrom
130
+ *
131
+ * @param data permit2 message with witness data to summarize
132
+ */
133
+ const extractPermitData = <T extends OperationTypeNames>(
134
+ data: YmaxPermitWitnessTransferFromData<T>,
135
+ ): PermitDataPayload => {
136
+ const witnessTypeStringExtractor = makeWitnessTypeStringExtractor({
137
+ encodeType,
138
+ });
139
+ // @ts-expect-error generic/union type compatibility
140
+ const permitData: YmaxPermitWitnessTransferFromData = data;
141
+
142
+ const witnessField = extractWitnessFieldFromTypes(permitData.types);
143
+ const { [witnessField.name]: witnessData, ...permit } = permitData.message;
144
+ const witness = hashStruct({
145
+ primaryType: witnessField.type,
146
+ types: permitData.types,
147
+ data: witnessData,
148
+ });
149
+ const witnessTypeString = witnessTypeStringExtractor(permitData.types);
150
+
151
+ const payload = {
152
+ chainId: permitData.domain!.chainId!,
153
+ permit,
154
+ witness,
155
+ witnessTypeString,
156
+ };
157
+
158
+ return payload;
159
+ };
160
+
161
+ /**
162
+ * Extract all details sufficient to handle any EIP-712 portfolio message,
163
+ * optionally with permit data.
164
+ *
165
+ * @param signedData
166
+ * @returns
167
+ */
168
+ const extractOperationDetailsFromSignedData = async <
169
+ T extends OperationTypeNames = OperationTypeNames,
170
+ >(
171
+ signedData: WithSignature<
172
+ YmaxPermitWitnessTransferFromData<T> | YmaxStandaloneOperationData<T>
173
+ >,
174
+ ): Promise<FullMessageDetails<T>> => {
175
+ const tokenOwner = await recoverTypedDataAddress(
176
+ signedData as RecoverTypedDataAddressParameters,
177
+ );
178
+ const { nonce, deadline } = (
179
+ signedData as unknown as
180
+ | YmaxPermitWitnessTransferFromData
181
+ | YmaxStandaloneOperationData
182
+ ).message;
183
+
184
+ if (isPermit2MessageType(signedData.primaryType)) {
185
+ const permit2Data =
186
+ signedData as unknown as YmaxPermitWitnessTransferFromData<T>;
187
+
188
+ const permitPayload = {
189
+ ...extractPermitData(permit2Data),
190
+ signature: signedData.signature,
191
+ };
192
+ const operationDetails =
193
+ extractOperationDetailsFromPermit2WitnessData(permit2Data);
194
+
195
+ return {
196
+ ...operationDetails,
197
+ permit: permitPayload,
198
+ evmWalletAddress: tokenOwner,
199
+ nonce,
200
+ deadline,
201
+ };
202
+ } else {
203
+ const standaloneData =
204
+ signedData as unknown as YmaxStandaloneOperationData<T>;
205
+ const operationDetails =
206
+ extractOperationDetailsFromStandaloneData(standaloneData);
207
+
208
+ return {
209
+ ...operationDetails,
210
+ evmWalletAddress: tokenOwner,
211
+ nonce,
212
+ deadline,
213
+ };
214
+ }
215
+ };
216
+
217
+ return {
218
+ extractOperationDetailsFromStandaloneData,
219
+ extractOperationDetailsFromPermit2WitnessData,
220
+ extractPermitData,
221
+ extractOperationDetailsFromSignedData,
222
+ };
223
+ };