@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.
@@ -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
+ };
@@ -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,
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/automation-sdk",
3
- "version": "1.2.27",
3
+ "version": "1.2.29",
4
4
  "description": "",
5
5
  "main": "./umd/index.js",
6
6
  "module": "./esm/index.js",
@@ -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
+ };