@defisaver/automation-sdk 1.2.27 → 1.2.29
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/esm/constants/index.js +20 -0
- package/esm/services/strategiesService.js +56 -0
- package/esm/services/strategySubService.d.ts +14 -0
- package/esm/services/strategySubService.js +22 -0
- package/esm/services/subDataService.d.ts +14 -0
- package/esm/services/subDataService.js +26 -0
- package/esm/services/triggerService.d.ts +34 -0
- package/esm/services/triggerService.js +71 -0
- package/esm/types/enums.d.ts +7 -2
- package/esm/types/enums.js +5 -0
- package/package.json +1 -1
- package/src/constants/index.ts +20 -0
- package/src/services/strategiesService.ts +76 -0
- package/src/services/strategySubService.ts +46 -0
- package/src/services/subDataService.ts +40 -0
- package/src/services/triggerService.ts +97 -0
- package/src/types/enums.ts +5 -0
- package/umd/index.js +2727 -566
- package/yarn-error.log +7233 -0
package/esm/constants/index.js
CHANGED
|
@@ -202,6 +202,26 @@ export const MAINNET_BUNDLES_INFO = {
|
|
|
202
202
|
strategyId: Strategies.Identifiers.Boost,
|
|
203
203
|
protocol: PROTOCOLS.Liquity,
|
|
204
204
|
},
|
|
205
|
+
[Bundles.MainnetIds.SPARK_REPAY]: {
|
|
206
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_REPAY,
|
|
207
|
+
strategyId: Strategies.Identifiers.Repay,
|
|
208
|
+
protocol: PROTOCOLS.Spark,
|
|
209
|
+
},
|
|
210
|
+
[Bundles.MainnetIds.SPARK_BOOST]: {
|
|
211
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_BOOST,
|
|
212
|
+
strategyId: Strategies.Identifiers.Boost,
|
|
213
|
+
protocol: PROTOCOLS.Spark,
|
|
214
|
+
},
|
|
215
|
+
[Bundles.MainnetIds.SPARK_CLOSE_TO_DEBT]: {
|
|
216
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_CLOSE_TO_DEBT,
|
|
217
|
+
strategyId: Strategies.Identifiers.CloseToDebt,
|
|
218
|
+
protocol: PROTOCOLS.Spark,
|
|
219
|
+
},
|
|
220
|
+
[Bundles.MainnetIds.SPARK_CLOSE_TO_COLLATERAL]: {
|
|
221
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_CLOSE_TO_COLLATERAL,
|
|
222
|
+
strategyId: Strategies.Identifiers.CloseToCollateral,
|
|
223
|
+
protocol: PROTOCOLS.Spark,
|
|
224
|
+
},
|
|
205
225
|
};
|
|
206
226
|
export const OPTIMISM_BUNDLES_INFO = {
|
|
207
227
|
[Bundles.OptimismIds.AAVE_V3_REPAY]: {
|
|
@@ -284,6 +284,56 @@ function parseLiquityLeverageManagement(position, parseData) {
|
|
|
284
284
|
_position.specific.mergeWithSameId = true;
|
|
285
285
|
return _position;
|
|
286
286
|
}
|
|
287
|
+
function parseSparkLeverageManagement(position, parseData) {
|
|
288
|
+
const _position = cloneDeep(position);
|
|
289
|
+
const { subStruct, subId } = parseData.subscriptionEventData;
|
|
290
|
+
const { isEnabled } = parseData.strategiesSubsData;
|
|
291
|
+
const triggerData = triggerService.sparkRatioTrigger.decode(subStruct.triggerData);
|
|
292
|
+
const subData = subDataService.sparkLeverageManagementSubData.decode(subStruct.subData);
|
|
293
|
+
_position.strategyData.decoded.triggerData = triggerData;
|
|
294
|
+
_position.strategyData.decoded.subData = subData;
|
|
295
|
+
const isRepay = _position.strategy.strategyId === Strategies.Identifiers.Repay;
|
|
296
|
+
if (isRepay) {
|
|
297
|
+
_position.specific = {
|
|
298
|
+
minRatio: triggerData.ratio,
|
|
299
|
+
minOptimalRatio: subData.targetRatio,
|
|
300
|
+
repayEnabled: true,
|
|
301
|
+
subId1: Number(subId),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
_position.specific = {
|
|
306
|
+
maxRatio: triggerData.ratio,
|
|
307
|
+
maxOptimalRatio: subData.targetRatio,
|
|
308
|
+
boostEnabled: isEnabled,
|
|
309
|
+
subId2: Number(subId),
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
_position.strategy.strategyId = Strategies.IdOverrides.LeverageManagement;
|
|
313
|
+
_position.specific.mergeWithSameId = true;
|
|
314
|
+
return _position;
|
|
315
|
+
}
|
|
316
|
+
function parseSparkCloseOnPrice(position, parseData) {
|
|
317
|
+
const _position = cloneDeep(position);
|
|
318
|
+
const { subStruct } = parseData.subscriptionEventData;
|
|
319
|
+
const triggerData = triggerService.sparkQuotePriceTrigger.decode(subStruct.triggerData);
|
|
320
|
+
const subData = subDataService.sparkQuotePriceSubData.decode(subStruct.subData);
|
|
321
|
+
_position.strategyData.decoded.triggerData = triggerData;
|
|
322
|
+
_position.strategyData.decoded.subData = subData;
|
|
323
|
+
_position.specific = {
|
|
324
|
+
collAsset: subData.collAsset,
|
|
325
|
+
collAssetId: subData.collAssetId,
|
|
326
|
+
debtAsset: subData.debtAsset,
|
|
327
|
+
debtAssetId: subData.debtAssetId,
|
|
328
|
+
baseToken: triggerData.baseTokenAddress,
|
|
329
|
+
quoteToken: triggerData.quoteTokenAddress,
|
|
330
|
+
price: triggerData.price,
|
|
331
|
+
ratioState: triggerData.ratioState,
|
|
332
|
+
};
|
|
333
|
+
const { ratioState } = getRatioStateInfoForAaveCloseStrategy(_position.specific.ratioState, wethToEthByAddress(_position.specific.collAsset, parseData.chainId), wethToEthByAddress(_position.specific.debtAsset, parseData.chainId), parseData.chainId);
|
|
334
|
+
_position.strategy.strategyId = isRatioStateOver(ratioState) ? Strategies.IdOverrides.TakeProfit : Strategies.IdOverrides.StopLoss;
|
|
335
|
+
return _position;
|
|
336
|
+
}
|
|
287
337
|
const parsingMethodsMapping = {
|
|
288
338
|
[ProtocolIdentifiers.StrategiesAutomation.MakerDAO]: {
|
|
289
339
|
[Strategies.Identifiers.SavingsLiqProtection]: parseMakerSavingsLiqProtection,
|
|
@@ -324,6 +374,12 @@ const parsingMethodsMapping = {
|
|
|
324
374
|
[Strategies.Identifiers.Dca]: parseExchangeDca,
|
|
325
375
|
[Strategies.Identifiers.LimitOrder]: parseExchangeLimitOrder,
|
|
326
376
|
},
|
|
377
|
+
[ProtocolIdentifiers.StrategiesAutomation.Spark]: {
|
|
378
|
+
[Strategies.Identifiers.Repay]: parseSparkLeverageManagement,
|
|
379
|
+
[Strategies.Identifiers.Boost]: parseSparkLeverageManagement,
|
|
380
|
+
[Strategies.Identifiers.CloseToDebt]: parseSparkCloseOnPrice,
|
|
381
|
+
[Strategies.Identifiers.CloseToCollateral]: parseSparkCloseOnPrice,
|
|
382
|
+
},
|
|
327
383
|
};
|
|
328
384
|
function getParsingMethod(id, strategy) {
|
|
329
385
|
return parsingMethodsMapping[id][strategy.strategyId];
|
|
@@ -39,3 +39,17 @@ export declare const exchangeEncode: {
|
|
|
39
39
|
dca(fromToken: EthereumAddress, toToken: EthereumAddress, amount: string, timestamp: number, interval: number, network: number): (boolean | string[] | Strategies.MainnetIds | Strategies.OptimismIds | Strategies.ArbitrumIds)[];
|
|
40
40
|
limitOrder(fromToken: EthereumAddress, toToken: EthereumAddress, amount: string, targetPrice: string, goodUntil: string, orderType: number): string[];
|
|
41
41
|
};
|
|
42
|
+
export declare const sparkEncode: {
|
|
43
|
+
leverageManagement(minRatio: number, maxRatio: number, maxOptimalRatio: number, minOptimalRatio: number, boostEnabled: boolean): string;
|
|
44
|
+
closeToAsset(strategyOrBundleId: number, isBundle: boolean | undefined, triggerData: {
|
|
45
|
+
baseTokenAddress: EthereumAddress;
|
|
46
|
+
quoteTokenAddress: EthereumAddress;
|
|
47
|
+
price: number;
|
|
48
|
+
ratioState: RatioState;
|
|
49
|
+
}, subData: {
|
|
50
|
+
collAsset: EthereumAddress;
|
|
51
|
+
collAssetId: number;
|
|
52
|
+
debtAsset: EthereumAddress;
|
|
53
|
+
debtAssetId: number;
|
|
54
|
+
}): (number | boolean | string[])[];
|
|
55
|
+
};
|
|
@@ -130,3 +130,25 @@ export const exchangeEncode = {
|
|
|
130
130
|
return subDataService.exchangeLimitOrderSubData.encode(fromToken, toToken, amount, targetPrice, goodUntil, orderType);
|
|
131
131
|
},
|
|
132
132
|
};
|
|
133
|
+
export const sparkEncode = {
|
|
134
|
+
leverageManagement(minRatio, maxRatio, maxOptimalRatio, minOptimalRatio, boostEnabled) {
|
|
135
|
+
let subInput = '0x';
|
|
136
|
+
subInput = subInput.concat(new Dec(minRatio).mul(1e16).toHex().slice(2)
|
|
137
|
+
.padStart(32, '0'));
|
|
138
|
+
subInput = subInput.concat(new Dec(maxRatio).mul(1e16).toHex().slice(2)
|
|
139
|
+
.padStart(32, '0'));
|
|
140
|
+
subInput = subInput.concat(new Dec(maxOptimalRatio).mul(1e16).toHex().slice(2)
|
|
141
|
+
.padStart(32, '0'));
|
|
142
|
+
subInput = subInput.concat(new Dec(minOptimalRatio).mul(1e16).toHex().slice(2)
|
|
143
|
+
.padStart(32, '0'));
|
|
144
|
+
subInput = subInput.concat(boostEnabled ? '01' : '00');
|
|
145
|
+
return subInput;
|
|
146
|
+
},
|
|
147
|
+
closeToAsset(strategyOrBundleId, isBundle = true, triggerData, subData) {
|
|
148
|
+
const { collAsset, collAssetId, debtAsset, debtAssetId, } = subData;
|
|
149
|
+
const subDataEncoded = subDataService.sparkQuotePriceSubData.encode(collAsset, collAssetId, debtAsset, debtAssetId);
|
|
150
|
+
const { baseTokenAddress, quoteTokenAddress, price, ratioState, } = triggerData;
|
|
151
|
+
const triggerDataEncoded = triggerService.sparkQuotePriceTrigger.encode(baseTokenAddress, quoteTokenAddress, price, ratioState);
|
|
152
|
+
return [strategyOrBundleId, isBundle, triggerDataEncoded, subDataEncoded];
|
|
153
|
+
},
|
|
154
|
+
};
|
|
@@ -95,3 +95,17 @@ export declare const exchangeLimitOrderSubData: {
|
|
|
95
95
|
amount: string;
|
|
96
96
|
};
|
|
97
97
|
};
|
|
98
|
+
export declare const sparkLeverageManagementSubData: {
|
|
99
|
+
decode(subData: string[]): {
|
|
100
|
+
targetRatio: number;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
export declare const sparkQuotePriceSubData: {
|
|
104
|
+
encode(collAsset: EthereumAddress, collAssetId: number, debtAsset: EthereumAddress, debtAssetId: number, nullAddress?: EthereumAddress): string[];
|
|
105
|
+
decode(subData: string[]): {
|
|
106
|
+
collAsset: EthereumAddress;
|
|
107
|
+
collAssetId: number;
|
|
108
|
+
debtAsset: EthereumAddress;
|
|
109
|
+
debtAssetId: number;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
@@ -226,3 +226,29 @@ export const exchangeLimitOrderSubData = {
|
|
|
226
226
|
return { fromToken, toToken, amount };
|
|
227
227
|
},
|
|
228
228
|
};
|
|
229
|
+
export const sparkLeverageManagementSubData = {
|
|
230
|
+
decode(subData) {
|
|
231
|
+
const ratioWei = mockedWeb3.eth.abi.decodeParameter('uint256', subData[0]);
|
|
232
|
+
const targetRatio = weiToRatioPercentage(ratioWei);
|
|
233
|
+
return { targetRatio };
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
export const sparkQuotePriceSubData = {
|
|
237
|
+
encode(collAsset, collAssetId, debtAsset, debtAssetId, nullAddress = ZERO_ADDRESS) {
|
|
238
|
+
const encodedColl = mockedWeb3.eth.abi.encodeParameter('address', collAsset);
|
|
239
|
+
const encodedCollId = mockedWeb3.eth.abi.encodeParameter('uint8', collAssetId);
|
|
240
|
+
const encodedDebt = mockedWeb3.eth.abi.encodeParameter('address', debtAsset);
|
|
241
|
+
const encodedDebtId = mockedWeb3.eth.abi.encodeParameter('uint8', debtAssetId);
|
|
242
|
+
const encodedNullAddress = mockedWeb3.eth.abi.encodeParameter('address', nullAddress);
|
|
243
|
+
return [encodedColl, encodedCollId, encodedDebt, encodedDebtId, encodedNullAddress];
|
|
244
|
+
},
|
|
245
|
+
decode(subData) {
|
|
246
|
+
const collAsset = mockedWeb3.eth.abi.decodeParameter('address', subData[0]);
|
|
247
|
+
const collAssetId = Number(mockedWeb3.eth.abi.decodeParameter('uint8', subData[1]));
|
|
248
|
+
const debtAsset = mockedWeb3.eth.abi.decodeParameter('address', subData[2]);
|
|
249
|
+
const debtAssetId = Number(mockedWeb3.eth.abi.decodeParameter('uint8', subData[3]));
|
|
250
|
+
return {
|
|
251
|
+
collAsset, collAssetId, debtAsset, debtAssetId,
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
};
|
|
@@ -112,3 +112,37 @@ export declare const exchangeOffchainPriceTrigger: {
|
|
|
112
112
|
goodUntil: any;
|
|
113
113
|
};
|
|
114
114
|
};
|
|
115
|
+
export declare const sparkRatioTrigger: {
|
|
116
|
+
encode(owner: EthereumAddress, market: EthereumAddress, ratioPercentage: number, ratioState: RatioState): string[];
|
|
117
|
+
decode(triggerData: string[]): {
|
|
118
|
+
owner: string;
|
|
119
|
+
market: string;
|
|
120
|
+
ratio: number;
|
|
121
|
+
ratioState: number;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
export declare const sparkQuotePriceTrigger: {
|
|
125
|
+
encode(baseTokenAddress: EthereumAddress, quoteTokenAddress: EthereumAddress, price: number, ratioState: RatioState): string[];
|
|
126
|
+
decode(triggerData: string[]): {
|
|
127
|
+
baseTokenAddress: EthereumAddress;
|
|
128
|
+
quoteTokenAddress: EthereumAddress;
|
|
129
|
+
price: string;
|
|
130
|
+
ratioState: RatioState;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
export declare const curveUsdBorrowRateTrigger: {
|
|
134
|
+
encode(market: EthereumAddress, targetRate: string, rateState: RatioState): string[];
|
|
135
|
+
decode(triggerData: string[]): {
|
|
136
|
+
market: EthereumAddress;
|
|
137
|
+
targetRate: string;
|
|
138
|
+
rateState: RatioState;
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
export declare const curveUsdSoftLiquidationTrigger: {
|
|
142
|
+
encode(market: EthereumAddress, owner: EthereumAddress, percentage: string): string[];
|
|
143
|
+
decode(triggerData: string[]): {
|
|
144
|
+
market: EthereumAddress;
|
|
145
|
+
owner: EthereumAddress;
|
|
146
|
+
percentage: string;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
@@ -189,3 +189,74 @@ export const exchangeOffchainPriceTrigger = {
|
|
|
189
189
|
};
|
|
190
190
|
},
|
|
191
191
|
};
|
|
192
|
+
export const sparkRatioTrigger = {
|
|
193
|
+
encode(owner, market, ratioPercentage, ratioState) {
|
|
194
|
+
const ratioWei = ratioPercentageToWei(ratioPercentage);
|
|
195
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'address', 'uint256', 'uint8'], [owner, market, ratioWei, ratioState])];
|
|
196
|
+
},
|
|
197
|
+
decode(triggerData) {
|
|
198
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'address', 'uint256', 'uint8'], triggerData[0]);
|
|
199
|
+
return {
|
|
200
|
+
owner: decodedData[0],
|
|
201
|
+
market: decodedData[1],
|
|
202
|
+
ratio: new Dec(mockedWeb3.utils.fromWei(decodedData[2])).mul(100).toNumber(),
|
|
203
|
+
ratioState: Number(decodedData[3]),
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
export const sparkQuotePriceTrigger = {
|
|
208
|
+
encode(baseTokenAddress, quoteTokenAddress, price, ratioState) {
|
|
209
|
+
// Price is always in 8 decimals
|
|
210
|
+
const _price = new Dec(price.toString()).mul(Math.pow(10, 8)).floor().toString();
|
|
211
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'address', 'uint256', 'uint8'], [baseTokenAddress, quoteTokenAddress, _price, ratioState])];
|
|
212
|
+
},
|
|
213
|
+
decode(triggerData) {
|
|
214
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'address', 'uint256', 'uint8'], triggerData[0]);
|
|
215
|
+
// Price is always in 8 decimals
|
|
216
|
+
const price = new Dec(decodedData[2]).div(Math.pow(10, 8)).toDP(8).toString();
|
|
217
|
+
return {
|
|
218
|
+
price,
|
|
219
|
+
baseTokenAddress: decodedData[0],
|
|
220
|
+
quoteTokenAddress: decodedData[1],
|
|
221
|
+
ratioState: +decodedData[3],
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
export const curveUsdBorrowRateTrigger = {
|
|
226
|
+
encode(market, targetRate, rateState) {
|
|
227
|
+
// the form is x = (e**(rate*365*86400))-1 where x*100 is number in %
|
|
228
|
+
// we reverse engineer that so we can calculate rate = ln(y/100 + 1) / 365*86400 where y is input in %
|
|
229
|
+
const rate = new Dec(new Dec(new Dec(targetRate).div(100)).plus(1)).ln().div(365).div(86400)
|
|
230
|
+
.toString();
|
|
231
|
+
const rateWei = mockedWeb3.utils.toWei(rate); // 18 decimals
|
|
232
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'uint256', 'uint8'], [market, rateWei, rateState])];
|
|
233
|
+
},
|
|
234
|
+
decode(triggerData) {
|
|
235
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'uint256', 'uint8'], triggerData[0]);
|
|
236
|
+
const rateEth = mockedWeb3.utils.fromWei(decodedData[1]);
|
|
237
|
+
// the form is x = (e**(rate*365*86400))-1 where x*100 is number in %
|
|
238
|
+
const exponentRate = new Dec(rateEth).mul(365).mul(86400);
|
|
239
|
+
const targetRate = new Dec(new Dec(2.718281828459).pow(exponentRate).minus(1)).mul(100)
|
|
240
|
+
.toString();
|
|
241
|
+
return {
|
|
242
|
+
market: decodedData[0],
|
|
243
|
+
targetRate,
|
|
244
|
+
rateState: +decodedData[2],
|
|
245
|
+
};
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
export const curveUsdSoftLiquidationTrigger = {
|
|
249
|
+
encode(market, owner, percentage) {
|
|
250
|
+
// 100% = 1e18 => 0.01 = 1e16
|
|
251
|
+
const _percentage = mockedWeb3.utils.toWei(percentage);
|
|
252
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'address', 'uint256'], [market, owner, _percentage])];
|
|
253
|
+
},
|
|
254
|
+
decode(triggerData) {
|
|
255
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'address', 'uint256'], triggerData[0]);
|
|
256
|
+
return {
|
|
257
|
+
market: decodedData[0],
|
|
258
|
+
owner: decodedData[1],
|
|
259
|
+
percentage: mockedWeb3.utils.fromWei(decodedData[2]),
|
|
260
|
+
};
|
|
261
|
+
},
|
|
262
|
+
};
|
package/esm/types/enums.d.ts
CHANGED
|
@@ -27,7 +27,8 @@ export declare namespace ProtocolIdentifiers {
|
|
|
27
27
|
CompoundV3 = "Compound__V3",
|
|
28
28
|
AaveV3 = "Aave__V3",
|
|
29
29
|
MorphoAaveV2 = "Morpho-Aave__V2",
|
|
30
|
-
Exchange = "Exchange"
|
|
30
|
+
Exchange = "Exchange",
|
|
31
|
+
Spark = "Spark"
|
|
31
32
|
}
|
|
32
33
|
enum LegacyAutomation {
|
|
33
34
|
MakerDAO = "MakerDAO",
|
|
@@ -100,7 +101,11 @@ export declare namespace Bundles {
|
|
|
100
101
|
MORPHO_AAVE_V2_REPAY = 14,
|
|
101
102
|
MORPHO_AAVE_V2_BOOST = 15,
|
|
102
103
|
LIQUITY_REPAY = 16,
|
|
103
|
-
LIQUITY_BOOST = 17
|
|
104
|
+
LIQUITY_BOOST = 17,
|
|
105
|
+
SPARK_REPAY = 18,
|
|
106
|
+
SPARK_BOOST = 19,
|
|
107
|
+
SPARK_CLOSE_TO_DEBT = 20,
|
|
108
|
+
SPARK_CLOSE_TO_COLLATERAL = 21
|
|
104
109
|
}
|
|
105
110
|
enum OptimismIds {
|
|
106
111
|
AAVE_V3_REPAY = 0,
|
package/esm/types/enums.js
CHANGED
|
@@ -33,6 +33,7 @@ export var ProtocolIdentifiers;
|
|
|
33
33
|
StrategiesAutomation["AaveV3"] = "Aave__V3";
|
|
34
34
|
StrategiesAutomation["MorphoAaveV2"] = "Morpho-Aave__V2";
|
|
35
35
|
StrategiesAutomation["Exchange"] = "Exchange";
|
|
36
|
+
StrategiesAutomation["Spark"] = "Spark";
|
|
36
37
|
})(StrategiesAutomation = ProtocolIdentifiers.StrategiesAutomation || (ProtocolIdentifiers.StrategiesAutomation = {}));
|
|
37
38
|
let LegacyAutomation;
|
|
38
39
|
(function (LegacyAutomation) {
|
|
@@ -115,6 +116,10 @@ export var Bundles;
|
|
|
115
116
|
MainnetIds[MainnetIds["MORPHO_AAVE_V2_BOOST"] = 15] = "MORPHO_AAVE_V2_BOOST";
|
|
116
117
|
MainnetIds[MainnetIds["LIQUITY_REPAY"] = 16] = "LIQUITY_REPAY";
|
|
117
118
|
MainnetIds[MainnetIds["LIQUITY_BOOST"] = 17] = "LIQUITY_BOOST";
|
|
119
|
+
MainnetIds[MainnetIds["SPARK_REPAY"] = 18] = "SPARK_REPAY";
|
|
120
|
+
MainnetIds[MainnetIds["SPARK_BOOST"] = 19] = "SPARK_BOOST";
|
|
121
|
+
MainnetIds[MainnetIds["SPARK_CLOSE_TO_DEBT"] = 20] = "SPARK_CLOSE_TO_DEBT";
|
|
122
|
+
MainnetIds[MainnetIds["SPARK_CLOSE_TO_COLLATERAL"] = 21] = "SPARK_CLOSE_TO_COLLATERAL";
|
|
118
123
|
})(MainnetIds = Bundles.MainnetIds || (Bundles.MainnetIds = {}));
|
|
119
124
|
let OptimismIds;
|
|
120
125
|
(function (OptimismIds) {
|
package/package.json
CHANGED
package/src/constants/index.ts
CHANGED
|
@@ -218,6 +218,26 @@ export const MAINNET_BUNDLES_INFO: MainnetBundleInfo = {
|
|
|
218
218
|
strategyId: Strategies.Identifiers.Boost,
|
|
219
219
|
protocol: PROTOCOLS.Liquity,
|
|
220
220
|
},
|
|
221
|
+
[Bundles.MainnetIds.SPARK_REPAY]: {
|
|
222
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_REPAY,
|
|
223
|
+
strategyId: Strategies.Identifiers.Repay,
|
|
224
|
+
protocol: PROTOCOLS.Spark,
|
|
225
|
+
},
|
|
226
|
+
[Bundles.MainnetIds.SPARK_BOOST]: {
|
|
227
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_BOOST,
|
|
228
|
+
strategyId: Strategies.Identifiers.Boost,
|
|
229
|
+
protocol: PROTOCOLS.Spark,
|
|
230
|
+
},
|
|
231
|
+
[Bundles.MainnetIds.SPARK_CLOSE_TO_DEBT]: {
|
|
232
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_CLOSE_TO_DEBT,
|
|
233
|
+
strategyId: Strategies.Identifiers.CloseToDebt,
|
|
234
|
+
protocol: PROTOCOLS.Spark,
|
|
235
|
+
},
|
|
236
|
+
[Bundles.MainnetIds.SPARK_CLOSE_TO_COLLATERAL]: {
|
|
237
|
+
strategyOrBundleId: Bundles.MainnetIds.SPARK_CLOSE_TO_COLLATERAL,
|
|
238
|
+
strategyId: Strategies.Identifiers.CloseToCollateral,
|
|
239
|
+
protocol: PROTOCOLS.Spark,
|
|
240
|
+
},
|
|
221
241
|
};
|
|
222
242
|
|
|
223
243
|
export const OPTIMISM_BUNDLES_INFO: OptimismBundleInfo = {
|
|
@@ -388,6 +388,76 @@ function parseLiquityLeverageManagement(position: Position.Automated, parseData:
|
|
|
388
388
|
return _position;
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
function parseSparkLeverageManagement(position: Position.Automated, parseData: ParseData): Position.Automated {
|
|
392
|
+
const _position = cloneDeep(position);
|
|
393
|
+
|
|
394
|
+
const { subStruct, subId } = parseData.subscriptionEventData;
|
|
395
|
+
const { isEnabled } = parseData.strategiesSubsData;
|
|
396
|
+
|
|
397
|
+
const triggerData = triggerService.sparkRatioTrigger.decode(subStruct.triggerData);
|
|
398
|
+
const subData = subDataService.sparkLeverageManagementSubData.decode(subStruct.subData);
|
|
399
|
+
|
|
400
|
+
_position.strategyData.decoded.triggerData = triggerData;
|
|
401
|
+
_position.strategyData.decoded.subData = subData;
|
|
402
|
+
|
|
403
|
+
const isRepay = _position.strategy.strategyId === Strategies.Identifiers.Repay;
|
|
404
|
+
|
|
405
|
+
if (isRepay) {
|
|
406
|
+
_position.specific = {
|
|
407
|
+
minRatio: triggerData.ratio,
|
|
408
|
+
minOptimalRatio: subData.targetRatio,
|
|
409
|
+
repayEnabled: true,
|
|
410
|
+
subId1: Number(subId),
|
|
411
|
+
};
|
|
412
|
+
} else {
|
|
413
|
+
_position.specific = {
|
|
414
|
+
maxRatio: triggerData.ratio,
|
|
415
|
+
maxOptimalRatio: subData.targetRatio,
|
|
416
|
+
boostEnabled: isEnabled,
|
|
417
|
+
subId2: Number(subId),
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
_position.strategy.strategyId = Strategies.IdOverrides.LeverageManagement;
|
|
422
|
+
_position.specific.mergeWithSameId = true;
|
|
423
|
+
|
|
424
|
+
return _position;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function parseSparkCloseOnPrice(position: Position.Automated, parseData: ParseData): Position.Automated {
|
|
428
|
+
const _position = cloneDeep(position);
|
|
429
|
+
|
|
430
|
+
const { subStruct } = parseData.subscriptionEventData;
|
|
431
|
+
|
|
432
|
+
const triggerData = triggerService.sparkQuotePriceTrigger.decode(subStruct.triggerData);
|
|
433
|
+
const subData = subDataService.sparkQuotePriceSubData.decode(subStruct.subData);
|
|
434
|
+
|
|
435
|
+
_position.strategyData.decoded.triggerData = triggerData;
|
|
436
|
+
_position.strategyData.decoded.subData = subData;
|
|
437
|
+
|
|
438
|
+
_position.specific = {
|
|
439
|
+
collAsset: subData.collAsset,
|
|
440
|
+
collAssetId: subData.collAssetId,
|
|
441
|
+
debtAsset: subData.debtAsset,
|
|
442
|
+
debtAssetId: subData.debtAssetId,
|
|
443
|
+
baseToken: triggerData.baseTokenAddress,
|
|
444
|
+
quoteToken: triggerData.quoteTokenAddress,
|
|
445
|
+
price: triggerData.price,
|
|
446
|
+
ratioState: triggerData.ratioState,
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
const { ratioState } = getRatioStateInfoForAaveCloseStrategy(
|
|
450
|
+
_position.specific.ratioState,
|
|
451
|
+
wethToEthByAddress(_position.specific.collAsset, parseData.chainId),
|
|
452
|
+
wethToEthByAddress(_position.specific.debtAsset, parseData.chainId),
|
|
453
|
+
parseData.chainId,
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
_position.strategy.strategyId = isRatioStateOver(ratioState) ? Strategies.IdOverrides.TakeProfit : Strategies.IdOverrides.StopLoss;
|
|
457
|
+
|
|
458
|
+
return _position;
|
|
459
|
+
}
|
|
460
|
+
|
|
391
461
|
const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
|
|
392
462
|
[ProtocolIdentifiers.StrategiesAutomation.MakerDAO]: {
|
|
393
463
|
[Strategies.Identifiers.SavingsLiqProtection]: parseMakerSavingsLiqProtection,
|
|
@@ -428,6 +498,12 @@ const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
|
|
|
428
498
|
[Strategies.Identifiers.Dca]: parseExchangeDca,
|
|
429
499
|
[Strategies.Identifiers.LimitOrder]: parseExchangeLimitOrder,
|
|
430
500
|
},
|
|
501
|
+
[ProtocolIdentifiers.StrategiesAutomation.Spark]: {
|
|
502
|
+
[Strategies.Identifiers.Repay]: parseSparkLeverageManagement,
|
|
503
|
+
[Strategies.Identifiers.Boost]: parseSparkLeverageManagement,
|
|
504
|
+
[Strategies.Identifiers.CloseToDebt]: parseSparkCloseOnPrice,
|
|
505
|
+
[Strategies.Identifiers.CloseToCollateral]: parseSparkCloseOnPrice,
|
|
506
|
+
},
|
|
431
507
|
};
|
|
432
508
|
|
|
433
509
|
function getParsingMethod(id: ProtocolIdentifiers.StrategiesAutomation, strategy: BundleOrStrategy) {
|
|
@@ -278,3 +278,49 @@ export const exchangeEncode = {
|
|
|
278
278
|
return subDataService.exchangeLimitOrderSubData.encode(fromToken, toToken, amount, targetPrice, goodUntil, orderType);
|
|
279
279
|
},
|
|
280
280
|
};
|
|
281
|
+
|
|
282
|
+
export const sparkEncode = {
|
|
283
|
+
leverageManagement(
|
|
284
|
+
minRatio: number,
|
|
285
|
+
maxRatio: number,
|
|
286
|
+
maxOptimalRatio: number,
|
|
287
|
+
minOptimalRatio: number,
|
|
288
|
+
boostEnabled: boolean,
|
|
289
|
+
) {
|
|
290
|
+
let subInput = '0x';
|
|
291
|
+
|
|
292
|
+
subInput = subInput.concat(new Dec(minRatio).mul(1e16).toHex().slice(2)
|
|
293
|
+
.padStart(32, '0'));
|
|
294
|
+
subInput = subInput.concat(new Dec(maxRatio).mul(1e16).toHex().slice(2)
|
|
295
|
+
.padStart(32, '0'));
|
|
296
|
+
subInput = subInput.concat(new Dec(maxOptimalRatio).mul(1e16).toHex().slice(2)
|
|
297
|
+
.padStart(32, '0'));
|
|
298
|
+
subInput = subInput.concat(new Dec(minOptimalRatio).mul(1e16).toHex().slice(2)
|
|
299
|
+
.padStart(32, '0'));
|
|
300
|
+
subInput = subInput.concat(boostEnabled ? '01' : '00');
|
|
301
|
+
|
|
302
|
+
return subInput;
|
|
303
|
+
},
|
|
304
|
+
closeToAsset(
|
|
305
|
+
strategyOrBundleId: number,
|
|
306
|
+
isBundle: boolean = true,
|
|
307
|
+
triggerData: {
|
|
308
|
+
baseTokenAddress: EthereumAddress, quoteTokenAddress: EthereumAddress, price: number, ratioState: RatioState
|
|
309
|
+
},
|
|
310
|
+
subData: {
|
|
311
|
+
collAsset: EthereumAddress, collAssetId: number, debtAsset: EthereumAddress, debtAssetId: number,
|
|
312
|
+
},
|
|
313
|
+
) {
|
|
314
|
+
const {
|
|
315
|
+
collAsset, collAssetId, debtAsset, debtAssetId,
|
|
316
|
+
} = subData;
|
|
317
|
+
const subDataEncoded = subDataService.sparkQuotePriceSubData.encode(collAsset, collAssetId, debtAsset, debtAssetId);
|
|
318
|
+
|
|
319
|
+
const {
|
|
320
|
+
baseTokenAddress, quoteTokenAddress, price, ratioState,
|
|
321
|
+
} = triggerData;
|
|
322
|
+
const triggerDataEncoded = triggerService.sparkQuotePriceTrigger.encode(baseTokenAddress, quoteTokenAddress, price, ratioState);
|
|
323
|
+
|
|
324
|
+
return [strategyOrBundleId, isBundle, triggerDataEncoded, subDataEncoded];
|
|
325
|
+
},
|
|
326
|
+
};
|
|
@@ -301,3 +301,43 @@ export const exchangeLimitOrderSubData = {
|
|
|
301
301
|
return { fromToken, toToken, amount };
|
|
302
302
|
},
|
|
303
303
|
};
|
|
304
|
+
|
|
305
|
+
export const sparkLeverageManagementSubData = { // TODO encode?
|
|
306
|
+
decode(subData: SubData): { targetRatio: number } {
|
|
307
|
+
const ratioWei = mockedWeb3.eth.abi.decodeParameter('uint256', subData[0]) as any as string;
|
|
308
|
+
const targetRatio = weiToRatioPercentage(ratioWei);
|
|
309
|
+
|
|
310
|
+
return { targetRatio };
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
export const sparkQuotePriceSubData = {
|
|
315
|
+
encode(
|
|
316
|
+
collAsset: EthereumAddress,
|
|
317
|
+
collAssetId: number,
|
|
318
|
+
debtAsset: EthereumAddress,
|
|
319
|
+
debtAssetId: number,
|
|
320
|
+
nullAddress: EthereumAddress = ZERO_ADDRESS,
|
|
321
|
+
): SubData {
|
|
322
|
+
const encodedColl = mockedWeb3.eth.abi.encodeParameter('address', collAsset);
|
|
323
|
+
const encodedCollId = mockedWeb3.eth.abi.encodeParameter('uint8', collAssetId);
|
|
324
|
+
|
|
325
|
+
const encodedDebt = mockedWeb3.eth.abi.encodeParameter('address', debtAsset);
|
|
326
|
+
const encodedDebtId = mockedWeb3.eth.abi.encodeParameter('uint8', debtAssetId);
|
|
327
|
+
|
|
328
|
+
const encodedNullAddress = mockedWeb3.eth.abi.encodeParameter('address', nullAddress);
|
|
329
|
+
|
|
330
|
+
return [encodedColl, encodedCollId, encodedDebt, encodedDebtId, encodedNullAddress];
|
|
331
|
+
},
|
|
332
|
+
decode(subData: SubData): { collAsset: EthereumAddress, collAssetId: number, debtAsset: EthereumAddress, debtAssetId: number } {
|
|
333
|
+
const collAsset = mockedWeb3.eth.abi.decodeParameter('address', subData[0]) as unknown as EthereumAddress;
|
|
334
|
+
const collAssetId = Number(mockedWeb3.eth.abi.decodeParameter('uint8', subData[1]));
|
|
335
|
+
|
|
336
|
+
const debtAsset = mockedWeb3.eth.abi.decodeParameter('address', subData[2]) as unknown as EthereumAddress;
|
|
337
|
+
const debtAssetId = Number(mockedWeb3.eth.abi.decodeParameter('uint8', subData[3]));
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
collAsset, collAssetId, debtAsset, debtAssetId,
|
|
341
|
+
};
|
|
342
|
+
},
|
|
343
|
+
};
|
|
@@ -236,3 +236,100 @@ export const exchangeOffchainPriceTrigger = {
|
|
|
236
236
|
};
|
|
237
237
|
},
|
|
238
238
|
};
|
|
239
|
+
|
|
240
|
+
export const sparkRatioTrigger = {
|
|
241
|
+
encode(owner: EthereumAddress, market: EthereumAddress, ratioPercentage: number, ratioState: RatioState) {
|
|
242
|
+
const ratioWei = ratioPercentageToWei(ratioPercentage);
|
|
243
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'address', 'uint256', 'uint8'], [owner, market, ratioWei, ratioState])];
|
|
244
|
+
},
|
|
245
|
+
decode(triggerData: TriggerData) {
|
|
246
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'address', 'uint256', 'uint8'], triggerData[0]) as string[];
|
|
247
|
+
return {
|
|
248
|
+
owner: decodedData[0],
|
|
249
|
+
market: decodedData[1],
|
|
250
|
+
ratio: new Dec(mockedWeb3.utils.fromWei(decodedData[2])).mul(100).toNumber(),
|
|
251
|
+
ratioState: Number(decodedData[3]),
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
export const sparkQuotePriceTrigger = {
|
|
257
|
+
encode(
|
|
258
|
+
baseTokenAddress: EthereumAddress,
|
|
259
|
+
quoteTokenAddress: EthereumAddress,
|
|
260
|
+
price: number,
|
|
261
|
+
ratioState: RatioState,
|
|
262
|
+
) {
|
|
263
|
+
// Price is always in 8 decimals
|
|
264
|
+
const _price = new Dec(price.toString()).mul(10 ** 8).floor().toString();
|
|
265
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'address', 'uint256', 'uint8'], [baseTokenAddress, quoteTokenAddress, _price, ratioState])];
|
|
266
|
+
},
|
|
267
|
+
decode(
|
|
268
|
+
triggerData: TriggerData,
|
|
269
|
+
): { baseTokenAddress: EthereumAddress, quoteTokenAddress: EthereumAddress, price: string, ratioState: RatioState } {
|
|
270
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'address', 'uint256', 'uint8'], triggerData[0]) as Array<string>;
|
|
271
|
+
// Price is always in 8 decimals
|
|
272
|
+
const price = new Dec(decodedData[2]).div(10 ** 8).toDP(8).toString();
|
|
273
|
+
return {
|
|
274
|
+
price,
|
|
275
|
+
baseTokenAddress: decodedData[0],
|
|
276
|
+
quoteTokenAddress: decodedData[1],
|
|
277
|
+
ratioState: +decodedData[3],
|
|
278
|
+
};
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const curveUsdBorrowRateTrigger = {
|
|
283
|
+
encode(
|
|
284
|
+
market: EthereumAddress,
|
|
285
|
+
targetRate: string,
|
|
286
|
+
rateState: RatioState,
|
|
287
|
+
) {
|
|
288
|
+
// the form is x = (e**(rate*365*86400))-1 where x*100 is number in %
|
|
289
|
+
// we reverse engineer that so we can calculate rate = ln(y/100 + 1) / 365*86400 where y is input in %
|
|
290
|
+
const rate = new Dec(new Dec(new Dec(targetRate).div(100)).plus(1)).ln().div(365).div(86400)
|
|
291
|
+
.toString();
|
|
292
|
+
const rateWei = mockedWeb3.utils.toWei(rate); // 18 decimals
|
|
293
|
+
|
|
294
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'uint256', 'uint8'], [market, rateWei, rateState])];
|
|
295
|
+
},
|
|
296
|
+
decode(
|
|
297
|
+
triggerData: TriggerData,
|
|
298
|
+
): { market: EthereumAddress, targetRate: string, rateState: RatioState } {
|
|
299
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'uint256', 'uint8'], triggerData[0]) as Array<string>;
|
|
300
|
+
const rateEth = mockedWeb3.utils.fromWei(decodedData[1]);
|
|
301
|
+
|
|
302
|
+
// the form is x = (e**(rate*365*86400))-1 where x*100 is number in %
|
|
303
|
+
const exponentRate = new Dec(rateEth).mul(365).mul(86400);
|
|
304
|
+
const targetRate = new Dec(new Dec(2.718281828459).pow(exponentRate).minus(1)).mul(100)
|
|
305
|
+
.toString();
|
|
306
|
+
return {
|
|
307
|
+
market: decodedData[0],
|
|
308
|
+
targetRate,
|
|
309
|
+
rateState: +decodedData[2],
|
|
310
|
+
};
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
export const curveUsdSoftLiquidationTrigger = {
|
|
315
|
+
encode(
|
|
316
|
+
market: EthereumAddress,
|
|
317
|
+
owner: EthereumAddress,
|
|
318
|
+
percentage: string,
|
|
319
|
+
) {
|
|
320
|
+
// 100% = 1e18 => 0.01 = 1e16
|
|
321
|
+
const _percentage = mockedWeb3.utils.toWei(percentage);
|
|
322
|
+
return [mockedWeb3.eth.abi.encodeParameters(['address', 'address', 'uint256'], [market, owner, _percentage])];
|
|
323
|
+
},
|
|
324
|
+
decode(
|
|
325
|
+
triggerData: TriggerData,
|
|
326
|
+
): { market: EthereumAddress, owner: EthereumAddress, percentage: string } {
|
|
327
|
+
const decodedData = mockedWeb3.eth.abi.decodeParameters(['address', 'address', 'uint256'], triggerData[0]) as Array<string>;
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
market: decodedData[0],
|
|
331
|
+
owner: decodedData[1],
|
|
332
|
+
percentage: mockedWeb3.utils.fromWei(decodedData[2]),
|
|
333
|
+
};
|
|
334
|
+
},
|
|
335
|
+
};
|