@defisaver/automation-sdk 3.1.3 → 3.1.4-dev-2

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.
Files changed (49) hide show
  1. package/cjs/automation/private/StrategiesAutomation.d.ts +2 -2
  2. package/cjs/automation/public/Strategies.test.d.ts +1 -0
  3. package/cjs/automation/public/Strategies.test.js +61 -0
  4. package/cjs/constants/index.js +35 -15
  5. package/cjs/services/strategiesService.js +68 -3
  6. package/cjs/services/strategySubService.d.ts +6 -2
  7. package/cjs/services/strategySubService.js +25 -3
  8. package/cjs/services/strategySubService.test.js +2 -2
  9. package/cjs/services/subDataService.d.ts +21 -2
  10. package/cjs/services/subDataService.js +56 -2
  11. package/cjs/services/subDataService.test.js +3 -3
  12. package/cjs/services/triggerService.d.ts +17 -0
  13. package/cjs/services/triggerService.js +33 -1
  14. package/cjs/services/utils.d.ts +6 -1
  15. package/cjs/services/utils.js +52 -1
  16. package/cjs/types/enums.d.ts +40 -11
  17. package/cjs/types/enums.js +37 -4
  18. package/cjs/types/index.d.ts +12 -3
  19. package/esm/automation/private/StrategiesAutomation.d.ts +2 -2
  20. package/esm/automation/public/Strategies.test.d.ts +1 -0
  21. package/esm/automation/public/Strategies.test.js +56 -0
  22. package/esm/constants/index.js +35 -15
  23. package/esm/services/strategiesService.js +69 -4
  24. package/esm/services/strategySubService.d.ts +6 -2
  25. package/esm/services/strategySubService.js +26 -4
  26. package/esm/services/strategySubService.test.js +2 -2
  27. package/esm/services/subDataService.d.ts +21 -2
  28. package/esm/services/subDataService.js +56 -2
  29. package/esm/services/subDataService.test.js +4 -4
  30. package/esm/services/triggerService.d.ts +17 -0
  31. package/esm/services/triggerService.js +32 -0
  32. package/esm/services/utils.d.ts +6 -1
  33. package/esm/services/utils.js +50 -1
  34. package/esm/types/enums.d.ts +40 -11
  35. package/esm/types/enums.js +36 -3
  36. package/esm/types/index.d.ts +12 -3
  37. package/package.json +1 -1
  38. package/src/automation/private/StrategiesAutomation.ts +2 -2
  39. package/src/automation/public/Strategies.test.ts +49 -0
  40. package/src/constants/index.ts +47 -16
  41. package/src/services/strategiesService.ts +89 -4
  42. package/src/services/strategySubService.test.ts +2 -2
  43. package/src/services/strategySubService.ts +52 -3
  44. package/src/services/subDataService.test.ts +4 -4
  45. package/src/services/subDataService.ts +85 -4
  46. package/src/services/triggerService.ts +53 -0
  47. package/src/services/utils.ts +60 -1
  48. package/src/types/enums.ts +36 -3
  49. package/src/types/index.ts +14 -2
@@ -19,7 +19,7 @@ import Automation from './Automation';
19
19
 
20
20
  interface IStrategiesAutomation extends Interfaces.Automation {
21
21
  chainId: ChainId,
22
- providerFork: Web3,
22
+ providerFork?: Web3,
23
23
  }
24
24
 
25
25
  export default class StrategiesAutomation extends Automation {
@@ -27,7 +27,7 @@ export default class StrategiesAutomation extends Automation {
27
27
 
28
28
  protected web3: Web3;
29
29
 
30
- protected web3Fork: Web3;
30
+ protected web3Fork?: Web3;
31
31
 
32
32
  protected subStorageContract: Contract.WithMeta<SubStorage>;
33
33
 
@@ -0,0 +1,49 @@
1
+ import Web3 from 'web3';
2
+ import { expect } from 'chai';
3
+
4
+ import {ChainId} from '../../types/enums';
5
+
6
+ import '../../configuration';
7
+ import EthereumStrategies from './EthereumStrategies';
8
+ import ArbitrumStrategies from './ArbitrumStrategies';
9
+ import OptimismStrategies from './OptimismStrategies';
10
+ import BaseStrategies from './BaseStrategies';
11
+
12
+ require('dotenv').config({ path: '.env' });
13
+
14
+ const Web3_1 = new Web3(process.env.RPC_1!);
15
+ const Web3_42161 = new Web3(process.env.RPC_42161!);
16
+ const Web3_10 = new Web3(process.env.RPC_10!);
17
+ const Web3_8453 = new Web3(process.env.RPC_8453!);
18
+
19
+ describe('Feature: StrategiesAutomation.ts', () => {
20
+ describe('Fetching subscriptions', () => {
21
+ it('can fetch subscriptions on Mainnet', async function () {
22
+ this.timeout(120000);
23
+ const ethStrategies = new EthereumStrategies({provider: Web3_1});
24
+ const subs = await ethStrategies.getSubscriptions({mergeSubs: true})
25
+ console.log(subs.length);
26
+ });
27
+
28
+ it('can fetch subscriptions on Arbitrum', async function () {
29
+ this.timeout(120000);
30
+ const arbiStrategies = new ArbitrumStrategies({provider: Web3_42161});
31
+ const subs = await arbiStrategies.getSubscriptions({mergeSubs: true})
32
+ console.log(subs.length);
33
+ });
34
+
35
+ it('can fetch subscriptions on Optimism', async function () {
36
+ this.timeout(120000);
37
+ const optimismStrategies = new OptimismStrategies({provider: Web3_10});
38
+ const subs = await optimismStrategies.getSubscriptions({mergeSubs: true})
39
+ console.log(subs.length);
40
+ });
41
+
42
+ it('can fetch subscriptions on Base', async function () {
43
+ this.timeout(120000);
44
+ const baseStrategies = new BaseStrategies({provider: Web3_8453});
45
+ const subs = await baseStrategies.getSubscriptions({mergeSubs: true})
46
+ console.log(subs.length);
47
+ });
48
+ });
49
+ });
@@ -1,5 +1,16 @@
1
1
  import type {
2
- ArbitrumBundleInfo, ArbitrumStrategiesInfo, BundlesInfo, EthereumAddress, Interfaces, MainnetBundleInfo, MainnetStrategiesInfo, OptimismBundleInfo, OptimismStrategiesInfo, BaseBundleInfo, BaseStrategiesInfo, StrategiesInfo,
2
+ ArbitrumBundleInfo,
3
+ ArbitrumStrategiesInfo,
4
+ BundlesInfo,
5
+ EthereumAddress,
6
+ Interfaces,
7
+ MainnetBundleInfo,
8
+ MainnetStrategiesInfo,
9
+ OptimismBundleInfo,
10
+ OptimismStrategiesInfo,
11
+ BaseBundleInfo,
12
+ BaseStrategiesInfo,
13
+ StrategiesInfo,
3
14
  } from '../types';
4
15
 
5
16
  import {
@@ -102,11 +113,6 @@ export const MAINNET_STRATEGIES_INFO: MainnetStrategiesInfo = {
102
113
  strategyId: Strategies.Identifiers.Payback,
103
114
  protocol: PROTOCOLS.CrvUSD,
104
115
  },
105
- [Strategies.MainnetIds.AAVE_V3_OPEN_ORDER_FROM_DEBT]: {
106
- strategyOrBundleId: Strategies.MainnetIds.AAVE_V3_OPEN_ORDER_FROM_DEBT,
107
- strategyId: Strategies.Identifiers.OpenOrderFromDebt,
108
- protocol: PROTOCOLS.AaveV3,
109
- },
110
116
  };
111
117
 
112
118
  export const OPTIMISM_STRATEGIES_INFO: OptimismStrategiesInfo = {
@@ -120,11 +126,6 @@ export const OPTIMISM_STRATEGIES_INFO: OptimismStrategiesInfo = {
120
126
  strategyId: Strategies.Identifiers.LimitOrder,
121
127
  protocol: PROTOCOLS.Exchange,
122
128
  },
123
- [Strategies.OptimismIds.AAVE_V3_OPEN_ORDER_FROM_DEBT]: {
124
- strategyOrBundleId: Strategies.OptimismIds.AAVE_V3_OPEN_ORDER_FROM_DEBT,
125
- strategyId: Strategies.Identifiers.OpenOrderFromDebt,
126
- protocol: PROTOCOLS.AaveV3,
127
- },
128
129
  };
129
130
 
130
131
  export const BASE_STRATEGIES_INFO: BaseStrategiesInfo = {
@@ -151,11 +152,6 @@ export const ARBITRUM_STRATEGIES_INFO: ArbitrumStrategiesInfo = {
151
152
  strategyId: Strategies.Identifiers.LimitOrder,
152
153
  protocol: PROTOCOLS.Exchange,
153
154
  },
154
- [Strategies.ArbitrumIds.AAVE_V3_OPEN_ORDER_FROM_DEBT]: {
155
- strategyOrBundleId: Strategies.ArbitrumIds.AAVE_V3_OPEN_ORDER_FROM_DEBT,
156
- strategyId: Strategies.Identifiers.OpenOrderFromDebt,
157
- protocol: PROTOCOLS.AaveV3,
158
- },
159
155
  };
160
156
 
161
157
  export const STRATEGIES_INFO: StrategiesInfo = {
@@ -375,6 +371,26 @@ export const MAINNET_BUNDLES_INFO: MainnetBundleInfo = {
375
371
  strategyId: Strategies.Identifiers.OpenOrderFromCollateral,
376
372
  protocol: PROTOCOLS.AaveV3,
377
373
  },
374
+ [Bundles.MainnetIds.AAVE_V3_REPAY_ON_PRICE]: {
375
+ strategyOrBundleId: Bundles.MainnetIds.AAVE_V3_REPAY_ON_PRICE,
376
+ strategyId: Strategies.Identifiers.RepayOnPrice,
377
+ protocol: PROTOCOLS.AaveV3,
378
+ },
379
+ [Bundles.MainnetIds.LIQUITY_V2_REPAY]: {
380
+ strategyOrBundleId: Bundles.MainnetIds.LIQUITY_V2_REPAY,
381
+ strategyId: Strategies.Identifiers.Repay,
382
+ protocol: PROTOCOLS.LiquityV2,
383
+ },
384
+ [Bundles.MainnetIds.LIQUITY_V2_BOOST]: {
385
+ strategyOrBundleId: Bundles.MainnetIds.LIQUITY_V2_BOOST,
386
+ strategyId: Strategies.Identifiers.Boost,
387
+ protocol: PROTOCOLS.LiquityV2,
388
+ },
389
+ [Bundles.MainnetIds.LIQUITY_V2_CLOSE]: {
390
+ strategyOrBundleId: Bundles.MainnetIds.LIQUITY_V2_CLOSE,
391
+ strategyId: Strategies.Identifiers.CloseOnPrice,
392
+ protocol: PROTOCOLS.LiquityV2,
393
+ },
378
394
  };
379
395
 
380
396
  export const OPTIMISM_BUNDLES_INFO: OptimismBundleInfo = {
@@ -403,6 +419,11 @@ export const OPTIMISM_BUNDLES_INFO: OptimismBundleInfo = {
403
419
  strategyId: Strategies.Identifiers.OpenOrderFromCollateral,
404
420
  protocol: PROTOCOLS.AaveV3,
405
421
  },
422
+ [Bundles.OptimismIds.AAVE_V3_REPAY_ON_PRICE]: {
423
+ strategyOrBundleId: Bundles.OptimismIds.AAVE_V3_REPAY_ON_PRICE,
424
+ strategyId: Strategies.Identifiers.RepayOnPrice,
425
+ protocol: PROTOCOLS.AaveV3,
426
+ },
406
427
  };
407
428
 
408
429
  export const BASE_BUNDLES_INFO: BaseBundleInfo = {
@@ -451,6 +472,11 @@ export const BASE_BUNDLES_INFO: BaseBundleInfo = {
451
472
  strategyId: Strategies.Identifiers.OpenOrderFromCollateral,
452
473
  protocol: PROTOCOLS.AaveV3,
453
474
  },
475
+ [Bundles.BaseIds.AAVE_V3_REPAY_ON_PRICE]: {
476
+ strategyOrBundleId: Bundles.BaseIds.AAVE_V3_REPAY_ON_PRICE,
477
+ strategyId: Strategies.Identifiers.RepayOnPrice,
478
+ protocol: PROTOCOLS.AaveV3,
479
+ },
454
480
  };
455
481
 
456
482
  export const ARBITRUM_BUNDLES_INFO: ArbitrumBundleInfo = {
@@ -489,6 +515,11 @@ export const ARBITRUM_BUNDLES_INFO: ArbitrumBundleInfo = {
489
515
  strategyId: Strategies.Identifiers.OpenOrderFromCollateral,
490
516
  protocol: PROTOCOLS.AaveV3,
491
517
  },
518
+ [Bundles.ArbitrumIds.AAVE_V3_REPAY_ON_PRICE]: {
519
+ strategyOrBundleId: Bundles.ArbitrumIds.AAVE_V3_REPAY_ON_PRICE,
520
+ strategyId: Strategies.Identifiers.RepayOnPrice,
521
+ protocol: PROTOCOLS.AaveV3,
522
+ },
492
523
  };
493
524
 
494
525
  export const BUNDLES_INFO: BundlesInfo = {
@@ -9,7 +9,7 @@ import type {
9
9
  import { ChainId, ProtocolIdentifiers, Strategies } from '../types/enums';
10
10
 
11
11
  import {
12
- getPositionId, getRatioStateInfoForAaveCloseStrategy, isRatioStateOver, wethToEthByAddress,
12
+ getPositionId, getRatioStateInfoForAaveCloseStrategy, getStopLossAndTakeProfitTypeByCloseStrategyType, isRatioStateOver, wethToEthByAddress,
13
13
  } from './utils';
14
14
  import * as subDataService from './subDataService';
15
15
  import * as triggerService from './triggerService';
@@ -563,6 +563,49 @@ function parseLiquityLeverageManagement(position: Position.Automated, parseData:
563
563
  return _position;
564
564
  }
565
565
 
566
+ function parseLiquityV2LeverageManagement(position: Position.Automated, parseData: ParseData): Position.Automated {
567
+ const _position = cloneDeep(position);
568
+
569
+ const { subStruct, subId, subHash } = parseData.subscriptionEventData;
570
+ const { isEnabled } = parseData.strategiesSubsData;
571
+
572
+ const triggerData = triggerService.liquityV2RatioTrigger.decode(subStruct.triggerData);
573
+ const subData = subDataService.liquityV2LeverageManagementSubData.decode(subStruct.subData);
574
+
575
+ _position.strategyData.decoded.triggerData = triggerData;
576
+ _position.strategyData.decoded.subData = subData;
577
+
578
+ _position.positionId = getPositionId(
579
+ _position.chainId, _position.protocol.id, _position.owner, triggerData.troveId, triggerData.market,
580
+ );
581
+
582
+ const isRepay = _position.strategy.strategyId === Strategies.Identifiers.Repay;
583
+
584
+ if (isRepay) {
585
+ _position.specific = {
586
+ triggerRepayRatio: triggerData.ratio,
587
+ targetRepayRatio: subData.targetRatio,
588
+ repayEnabled: isEnabled,
589
+ subId1: Number(subId),
590
+ subHashRepay: subHash,
591
+ mergeWithId: Strategies.Identifiers.Boost,
592
+ };
593
+ } else {
594
+ _position.specific = {
595
+ triggerBoostRatio: triggerData.ratio,
596
+ targetBoostRatio: subData.targetRatio,
597
+ boostEnabled: isEnabled,
598
+ subId2: Number(subId),
599
+ subHashBoost: subHash,
600
+ mergeId: Strategies.Identifiers.Boost,
601
+ };
602
+ }
603
+
604
+ _position.strategy.strategyId = Strategies.IdOverrides.LeverageManagement;
605
+
606
+ return _position;
607
+ }
608
+
566
609
  function parseSparkLeverageManagement(position: Position.Automated, parseData: ParseData): Position.Automated {
567
610
  const _position = cloneDeep(position);
568
611
 
@@ -779,13 +822,13 @@ function parseMorphoBlueLeverageManagement(position: Position.Automated, parseDa
779
822
  return _position;
780
823
  }
781
824
 
782
- function parseAaveV3OpenOrderFromCollateral(position: Position.Automated, parseData: ParseData): Position.Automated {
825
+ function parseAaveV3LeverageManagementOnPrice(position: Position.Automated, parseData: ParseData): Position.Automated {
783
826
  const _position = cloneDeep(position);
784
827
 
785
828
  const { subStruct } = parseData.subscriptionEventData;
786
829
 
787
830
  const triggerData = triggerService.aaveV3QuotePriceTrigger.decode(subStruct.triggerData);
788
- const subData = subDataService.aaveV3OpenOrderSubData.decode(subStruct.subData);
831
+ const subData = subDataService.aaveV3LeverageManagementOnPriceSubData.decode(subStruct.subData);
789
832
 
790
833
  _position.strategyData.decoded.triggerData = triggerData;
791
834
  _position.strategyData.decoded.subData = subData;
@@ -806,6 +849,42 @@ function parseAaveV3OpenOrderFromCollateral(position: Position.Automated, parseD
806
849
  return _position;
807
850
  }
808
851
 
852
+ function parseLiquityV2CloseOnPrice(position: Position.Automated, parseData: ParseData): Position.Automated {
853
+ const _position = cloneDeep(position);
854
+
855
+ const { subStruct } = parseData.subscriptionEventData;
856
+
857
+ const triggerData = triggerService.closePriceTrigger.decode(subStruct.triggerData);
858
+ const subData = subDataService.liquityV2CloseSubData.decode(subStruct.subData);
859
+
860
+ _position.strategyData.decoded.triggerData = triggerData;
861
+ _position.strategyData.decoded.subData = subData;
862
+
863
+ _position.positionId = getPositionId(
864
+ _position.chainId, _position.protocol.id, _position.owner, subData.troveId, subData.market,
865
+ );
866
+
867
+ const { takeProfitType, stopLossType } = getStopLossAndTakeProfitTypeByCloseStrategyType(+subData.closeType);
868
+
869
+ // User can have:
870
+ // - Only TakeProfit
871
+ // - Only StopLoss
872
+ // - Both
873
+ // TODO: see on frontend what specific data we need here because stop-loss and take-profit is one bundle now
874
+ _position.strategy.strategyId = Strategies.Identifiers.CloseOnPrice;
875
+ _position.specific = {
876
+ market: subData.market,
877
+ troveId: subData.troveId,
878
+ stopLossPrice: triggerData.lowerPrice,
879
+ takeProfitPrice: triggerData.upperPrice,
880
+ closeToAssetAddr: triggerData.tokenAddr,
881
+ takeProfitType,
882
+ stopLossType,
883
+ };
884
+
885
+ return _position;
886
+ }
887
+
809
888
  const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
810
889
  [ProtocolIdentifiers.StrategiesAutomation.MakerDAO]: {
811
890
  [Strategies.Identifiers.SavingsLiqProtection]: parseMakerSavingsLiqProtection,
@@ -826,6 +905,11 @@ const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
826
905
  [Strategies.Identifiers.SavingsDsrSupply]: parseLiquitySavingsLiqProtection,
827
906
  [Strategies.Identifiers.DebtInFrontRepay]: parseLiquityDebtInFrontRepay,
828
907
  },
908
+ [ProtocolIdentifiers.StrategiesAutomation.LiquityV2]: {
909
+ [Strategies.Identifiers.Repay]: parseLiquityV2LeverageManagement,
910
+ [Strategies.Identifiers.Boost]: parseLiquityV2LeverageManagement,
911
+ [Strategies.Identifiers.CloseOnPrice]: parseLiquityV2CloseOnPrice,
912
+ },
829
913
  [ProtocolIdentifiers.StrategiesAutomation.AaveV2]: {
830
914
  [Strategies.Identifiers.Repay]: parseAaveV2LeverageManagement,
831
915
  [Strategies.Identifiers.Boost]: parseAaveV2LeverageManagement,
@@ -837,7 +921,8 @@ const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
837
921
  [Strategies.Identifiers.CloseToDebtWithGasPrice]: parseAaveV3CloseOnPriceWithMaximumGasPrice,
838
922
  [Strategies.Identifiers.CloseToCollateral]: parseAaveV3CloseOnPrice,
839
923
  [Strategies.Identifiers.CloseToCollateralWithGasPrice]: parseAaveV3CloseOnPriceWithMaximumGasPrice,
840
- [Strategies.Identifiers.OpenOrderFromCollateral]: parseAaveV3OpenOrderFromCollateral,
924
+ [Strategies.Identifiers.OpenOrderFromCollateral]: parseAaveV3LeverageManagementOnPrice,
925
+ [Strategies.Identifiers.RepayOnPrice]: parseAaveV3LeverageManagementOnPrice,
841
926
  },
842
927
  [ProtocolIdentifiers.StrategiesAutomation.CompoundV2]: {
843
928
  [Strategies.Identifiers.Repay]: parseCompoundV2LeverageManagement,
@@ -565,7 +565,7 @@ describe('Feature: strategySubService.ts', () => {
565
565
  });
566
566
  });
567
567
 
568
- describe('openOrder()', () => {
568
+ describe('leverageManagementOnPrice()', () => {
569
569
  const examples: Array<[
570
570
  [StrategyOrBundleIds, boolean, TriggerData, SubData],
571
571
  [
@@ -614,7 +614,7 @@ describe('Feature: strategySubService.ts', () => {
614
614
 
615
615
  examples.forEach(([expected, actual]) => {
616
616
  it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
617
- expect(aaveV3Encode.openOrder(...actual)).to.eql(expected);
617
+ expect(aaveV3Encode.leverageManagementOnPrice(...actual)).to.eql(expected);
618
618
  });
619
619
  });
620
620
  });
@@ -3,6 +3,7 @@ import { getAssetInfo } from '@defisaver/tokens';
3
3
 
4
4
  import type { OrderType } from '../types/enums';
5
5
  import {
6
+ CloseStrategyType, CloseToAssetType,
6
7
  Bundles, ChainId, RatioState, Strategies,
7
8
  } from '../types/enums';
8
9
  import type { EthereumAddress, StrategyOrBundleIds } from '../types';
@@ -11,7 +12,9 @@ import { STRATEGY_IDS } from '../constants';
11
12
 
12
13
  import * as subDataService from './subDataService';
13
14
  import * as triggerService from './triggerService';
14
- import { compareAddresses, requireAddress, requireAddresses } from './utils';
15
+ import {
16
+ compareAddresses, getCloseStrategyType, requireAddress, requireAddresses,
17
+ } from './utils';
15
18
 
16
19
  export const makerEncode = {
17
20
  repayFromSavings(
@@ -298,7 +301,7 @@ export const aaveV3Encode = {
298
301
 
299
302
  return [strategyOrBundleId, isBundle, triggerDataEncoded, subDataEncoded];
300
303
  },
301
- openOrder(
304
+ leverageManagementOnPrice(
302
305
  strategyOrBundleId: number,
303
306
  isBundle: boolean = true,
304
307
  triggerData: {
@@ -311,7 +314,7 @@ export const aaveV3Encode = {
311
314
  const {
312
315
  collAsset, collAssetId, debtAsset, debtAssetId, marketAddr, targetRatio,
313
316
  } = subData;
314
- const subDataEncoded = subDataService.aaveV3OpenOrderSubData.encode(collAsset, collAssetId, debtAsset, debtAssetId, marketAddr, targetRatio);
317
+ const subDataEncoded = subDataService.aaveV3LeverageManagementOnPriceSubData.encode(collAsset, collAssetId, debtAsset, debtAssetId, marketAddr, targetRatio);
315
318
 
316
319
  const {
317
320
  baseTokenAddress, quoteTokenAddress, price, state,
@@ -522,3 +525,49 @@ export const morphoBlueEncode = {
522
525
  return [strategyOrBundleId, isBundle, triggerData, subData];
523
526
  },
524
527
  };
528
+
529
+ export const liquityV2Encode = {
530
+ leverageManagement(
531
+ market: EthereumAddress,
532
+ troveId: string,
533
+ ratioState: RatioState,
534
+ targetRatio: number,
535
+ triggerRatio: number,
536
+ strategyOrBundleId: number,
537
+ ) {
538
+ const isBundle = true;
539
+ const isRepay = ratioState === RatioState.UNDER;
540
+
541
+ const subData = subDataService.liquityV2LeverageManagementSubData.encode(market, troveId, ratioState, targetRatio);
542
+ const triggerData = triggerService.liquityV2RatioTrigger.encode(market, troveId, triggerRatio, ratioState);
543
+
544
+ // TODO: we can hardcode right bundles after testing
545
+ // const strategyOrBundleId = ratioState === RatioState.OVER
546
+ // ? Bundles.MainnetIds.LIQUITY_V2_BOOST
547
+ // : Bundles.MainnetIds.LIQUITY_V2_REPAY;
548
+
549
+ return [strategyOrBundleId, isBundle, triggerData, subData];
550
+ },
551
+ closeOnPrice(
552
+ strategyOrBundleId: number,
553
+ market: EthereumAddress,
554
+ troveId: string,
555
+ collToken: EthereumAddress,
556
+ boldToken: EthereumAddress,
557
+ stopLossPrice: number = 0,
558
+ stopLossType: CloseToAssetType = CloseToAssetType.DEBT,
559
+ takeProfitPrice: number = 0,
560
+ takeProfitType: CloseToAssetType = CloseToAssetType.COLLATERAL,
561
+ ) {
562
+ const isBundle = true;
563
+ const closeType = getCloseStrategyType(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType);
564
+
565
+ const subData = subDataService.liquityV2CloseSubData.encode(market, troveId, collToken, boldToken, closeType);
566
+ const triggerData = triggerService.closePriceTrigger.encode(collToken, stopLossPrice, takeProfitPrice);
567
+
568
+ // TODO: we can hardcode bundleID after testing
569
+ // Bundles.MainnetIds.LIQUITY_V2_CLOSE;
570
+
571
+ return [strategyOrBundleId, isBundle, triggerData, subData];
572
+ },
573
+ };
@@ -31,7 +31,7 @@ import {
31
31
  sparkQuotePriceSubData,
32
32
  crvUSDLeverageManagementSubData,
33
33
  compoundV3L2LeverageManagementSubData, morphoBlueLeverageManagementSubData, crvUSDPaybackSubData,
34
- aaveV3OpenOrderSubData,
34
+ aaveV3LeverageManagementOnPriceSubData,
35
35
  } from './subDataService';
36
36
  import { AAVE_V3_VARIABLE_BORROW_RATE } from '../constants';
37
37
 
@@ -1324,7 +1324,7 @@ describe('Feature: subDataService.ts', () => {
1324
1324
  });
1325
1325
  });
1326
1326
 
1327
- describe('When testing subDataService.aaveV3OpenOrderSubData', () => {
1327
+ describe('When testing subDataService.aaveV3LeverageManagementOnPriceSubData', () => {
1328
1328
  describe('encode()', () => {
1329
1329
  const examples: Array<[SubData, [collAsset: EthereumAddress, collAssetId: number, debtAsset: EthereumAddress, debtAssetId: number, marketAddr: EthereumAddress, targetRatio: number]]> = [
1330
1330
  [
@@ -1350,7 +1350,7 @@ describe('Feature: subDataService.ts', () => {
1350
1350
 
1351
1351
  examples.forEach(([expected, actual]) => {
1352
1352
  it(`Given ${actual} should return expected value: ${expected}`, () => {
1353
- expect(aaveV3OpenOrderSubData.encode(...actual)).to.eql(expected);
1353
+ expect(aaveV3LeverageManagementOnPriceSubData.encode(...actual)).to.eql(expected);
1354
1354
  });
1355
1355
  });
1356
1356
  });
@@ -1379,7 +1379,7 @@ describe('Feature: subDataService.ts', () => {
1379
1379
 
1380
1380
  examples.forEach(([expected, actual]) => {
1381
1381
  it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1382
- expect(aaveV3OpenOrderSubData.decode(actual)).to.eql(expected);
1382
+ expect(aaveV3LeverageManagementOnPriceSubData.decode(actual)).to.eql(expected);
1383
1383
  });
1384
1384
  });
1385
1385
  });
@@ -6,8 +6,10 @@ import { assetAmountInEth, getAssetInfo, getAssetInfoByAddress } from '@defisave
6
6
  import { otherAddresses } from '@defisaver/sdk';
7
7
 
8
8
  import type { SubData, EthereumAddress } from '../types';
9
- import type { OrderType } from '../types/enums';
10
- import { ChainId, RatioState } from '../types/enums';
9
+ import type { CloseStrategyType, OrderType } from '../types/enums';
10
+ import {
11
+ ChainId, CollActionType, DebtActionType, RatioState,
12
+ } from '../types/enums';
11
13
 
12
14
  import { AAVE_V3_VARIABLE_BORROW_RATE, ZERO_ADDRESS } from '../constants';
13
15
 
@@ -594,7 +596,7 @@ export const morphoBlueLeverageManagementSubData = {
594
596
  },
595
597
  };
596
598
 
597
- export const aaveV3OpenOrderSubData = {
599
+ export const aaveV3LeverageManagementOnPriceSubData = {
598
600
  encode(
599
601
  collAsset: EthereumAddress,
600
602
  collAssetId: number,
@@ -642,4 +644,83 @@ export const aaveV3OpenOrderSubData = {
642
644
  collAsset, collAssetId, debtAsset, debtAssetId, marketAddr, targetRatio,
643
645
  };
644
646
  },
645
- };
647
+ };
648
+
649
+ export const liquityV2LeverageManagementSubData = {
650
+ encode: (
651
+ market: EthereumAddress,
652
+ troveId: string,
653
+ ratioState: RatioState,
654
+ targetRatio: number,
655
+ ) => {
656
+ const marketEncoded = AbiCoder.encodeParameter('address', market);
657
+ const troveIdEncoded = AbiCoder.encodeParameter('uint256', troveId);
658
+ const ratioStateEncoded = AbiCoder.encodeParameter('uint8', ratioState);
659
+ const targetRatioEncoded = AbiCoder.encodeParameter('uint256', ratioPercentageToWei(targetRatio));
660
+
661
+ const isRepay = ratioState === RatioState.UNDER;
662
+ const collActionType = isRepay ? CollActionType.WITHDRAW : CollActionType.SUPPLY;
663
+ const debtActionType = isRepay ? DebtActionType.PAYBACK : DebtActionType.BORROW;
664
+
665
+ const collActionTypeEncoded = AbiCoder.encodeParameter('uint8', collActionType);
666
+ const debtActionTypeEncoded = AbiCoder.encodeParameter('uint8', debtActionType);
667
+
668
+ return [marketEncoded, troveIdEncoded, ratioStateEncoded, targetRatioEncoded, collActionTypeEncoded, debtActionTypeEncoded];
669
+ },
670
+ decode: (subData: SubData) => {
671
+ const market = AbiCoder.decodeParameter('address', subData[0]) as unknown as EthereumAddress;
672
+ const troveId = AbiCoder.decodeParameter('uint256', subData[1]) as any as string;
673
+ const ratioState = AbiCoder.decodeParameter('uint8', subData[2]) as any as RatioState;
674
+ const weiRatio = AbiCoder.decodeParameter('uint256', subData[3]) as any as string;
675
+ const targetRatio = weiToRatioPercentage(weiRatio);
676
+
677
+ return {
678
+ market, troveId, ratioState, targetRatio,
679
+ };
680
+ },
681
+ };
682
+
683
+ export const liquityV2CloseSubData = {
684
+ encode(
685
+ market: EthereumAddress,
686
+ troveId: string,
687
+ collToken: EthereumAddress,
688
+ boldToken: EthereumAddress,
689
+ closeType: CloseStrategyType,
690
+ ): SubData {
691
+ const marketEncoded = AbiCoder.encodeParameter('address', market);
692
+ const troveIdEncoded = AbiCoder.encodeParameter('uint256', troveId);
693
+ const collAddrEncoded = AbiCoder.encodeParameter('address', collToken);
694
+ const boldTokenEncoded = AbiCoder.encodeParameter('address', boldToken);
695
+ const wethAddress = getAssetInfo('WETH').address;
696
+ const wethAddressEncoded = AbiCoder.encodeParameter('address', wethAddress);
697
+ const closeTypeEncoded = AbiCoder.encodeParameter('uint8', closeType);
698
+
699
+ return [
700
+ marketEncoded,
701
+ troveIdEncoded,
702
+ collAddrEncoded,
703
+ boldTokenEncoded,
704
+ wethAddressEncoded,
705
+ closeTypeEncoded,
706
+ ];
707
+ },
708
+ decode(subData: SubData): {
709
+ market: EthereumAddress,
710
+ troveId: string,
711
+ collToken: EthereumAddress,
712
+ boldToken: EthereumAddress,
713
+ closeType: CloseStrategyType,
714
+ } {
715
+ const market = AbiCoder.decodeParameter('address', subData[0]) as unknown as EthereumAddress;
716
+ const troveId = AbiCoder.decodeParameter('uint256', subData[1]) as any as string;
717
+ const collToken = AbiCoder.decodeParameter('address', subData[2]) as any as EthereumAddress;
718
+ const boldToken = AbiCoder.decodeParameter('address', subData[3]) as any as EthereumAddress;
719
+ // skip wethAddress
720
+ const closeType = AbiCoder.decodeParameter('uint8', subData[5]) as any as CloseStrategyType;
721
+
722
+ return {
723
+ market, troveId, collToken, boldToken, closeType,
724
+ };
725
+ },
726
+ };
@@ -447,3 +447,56 @@ export const morphoBlueRatioTrigger = {
447
447
  };
448
448
  },
449
449
  };
450
+
451
+ export const liquityV2RatioTrigger = {
452
+ encode(
453
+ market: EthereumAddress,
454
+ troveId: string,
455
+ ratioPercentage: number,
456
+ ratioState: RatioState,
457
+ ) {
458
+ const ratioWei = ratioPercentageToWei(ratioPercentage);
459
+ return [AbiCoder.encodeParameters(['address', 'uint256', 'uint256', 'uint8'], [market, troveId, ratioWei, ratioState])];
460
+ },
461
+ decode(
462
+ triggerData: TriggerData,
463
+ ) {
464
+ const decodedData = AbiCoder.decodeParameters(['address', 'uint256', 'uint256', 'uint8'], triggerData[0]);
465
+ return {
466
+ market: decodedData[0] as EthereumAddress,
467
+ troveId: decodedData[1] as string,
468
+ ratio: weiToRatioPercentage(decodedData[2] as string),
469
+ ratioState: Number(decodedData[3]),
470
+ };
471
+ },
472
+ };
473
+
474
+ export const closePriceTrigger = {
475
+ encode(
476
+ tokenAddr: EthereumAddress,
477
+ lowerPrice: number,
478
+ upperPrice: number,
479
+ ) {
480
+ const lowerPriceFormatted = new Dec(lowerPrice).mul(1e8).floor().toString();
481
+ const upperPriceFormatted = new Dec(upperPrice).mul(1e8).floor().toString();
482
+
483
+ return [
484
+ AbiCoder.encodeParameters(
485
+ ['address', 'uint256', 'uint256'],
486
+ [tokenAddr, lowerPriceFormatted, upperPriceFormatted],
487
+ ),
488
+ ];
489
+ },
490
+ decode(triggerData: TriggerData): {
491
+ tokenAddr: EthereumAddress,
492
+ lowerPrice: string,
493
+ upperPrice: string,
494
+ } {
495
+ const decodedData = AbiCoder.decodeParameters(['address', 'uint256', 'uint256'], triggerData[0]);
496
+ return {
497
+ tokenAddr: decodedData[0] as EthereumAddress,
498
+ lowerPrice: new Dec(decodedData[1] as string).div(1e8).toString(),
499
+ upperPrice: new Dec(decodedData[2] as string).div(1e8).toString(),
500
+ };
501
+ },
502
+ };