@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 +4 -4
- package/src/evm-wallet/eip712-messages.d.ts +152 -0
- package/src/evm-wallet/eip712-messages.d.ts.map +1 -0
- package/src/evm-wallet/eip712-messages.ts +286 -0
- package/src/evm-wallet/message-handler-helpers.d.ts +43 -0
- package/src/evm-wallet/message-handler-helpers.d.ts.map +1 -0
- package/src/evm-wallet/message-handler-helpers.ts +223 -0
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-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-
|
|
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-
|
|
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": "
|
|
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
|
+
};
|