@defisaver/automation-sdk 3.1.1-dev → 3.1.1-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.
@@ -373,6 +373,11 @@ exports.MAINNET_BUNDLES_INFO = {
373
373
  strategyId: enums_1.Strategies.Identifiers.Boost,
374
374
  protocol: exports.PROTOCOLS.LiquityV2,
375
375
  },
376
+ [enums_1.Bundles.MainnetIds.LIQUITY_V2_CLOSE]: {
377
+ strategyOrBundleId: enums_1.Bundles.MainnetIds.LIQUITY_V2_CLOSE,
378
+ strategyId: enums_1.Strategies.Identifiers.CloseOnPrice,
379
+ protocol: exports.PROTOCOLS.LiquityV2,
380
+ },
376
381
  };
377
382
  exports.OPTIMISM_BUNDLES_INFO = {
378
383
  [enums_1.Bundles.OptimismIds.AAVE_V3_REPAY]: {
@@ -431,7 +431,7 @@ function parseLiquityLeverageManagement(position, parseData) {
431
431
  }
432
432
  function parseLiquityV2LeverageManagement(position, parseData) {
433
433
  const _position = (0, lodash_1.cloneDeep)(position);
434
- const { subStruct, subId } = parseData.subscriptionEventData;
434
+ const { subStruct, subId, subHash } = parseData.subscriptionEventData;
435
435
  const { isEnabled } = parseData.strategiesSubsData;
436
436
  const triggerData = triggerService.liquityV2RatioTrigger.decode(subStruct.triggerData);
437
437
  const subData = subDataService.liquityV2LeverageManagementSubData.decode(subStruct.subData);
@@ -443,8 +443,9 @@ function parseLiquityV2LeverageManagement(position, parseData) {
443
443
  _position.specific = {
444
444
  triggerRepayRatio: triggerData.ratio,
445
445
  targetRepayRatio: subData.targetRatio,
446
- repayEnabled: true,
446
+ repayEnabled: isEnabled,
447
447
  subId1: Number(subId),
448
+ subHashRepay: subHash,
448
449
  mergeWithId: enums_1.Strategies.Identifiers.Boost,
449
450
  };
450
451
  }
@@ -454,6 +455,7 @@ function parseLiquityV2LeverageManagement(position, parseData) {
454
455
  targetBoostRatio: subData.targetRatio,
455
456
  boostEnabled: isEnabled,
456
457
  subId2: Number(subId),
458
+ subHashBoost: subHash,
457
459
  mergeId: enums_1.Strategies.Identifiers.Boost,
458
460
  };
459
461
  }
@@ -642,6 +644,23 @@ function parseAaveV3OpenOrderFromCollateral(position, parseData) {
642
644
  };
643
645
  return _position;
644
646
  }
647
+ function parseLiquityV2CloseOnPrice(position, parseData) {
648
+ const _position = (0, lodash_1.cloneDeep)(position);
649
+ const { subStruct } = parseData.subscriptionEventData;
650
+ const triggerData = triggerService.shouldClosePriceTrigger.decode(subStruct.triggerData);
651
+ const subData = subDataService.liquityV2CloseSubData.decode(subStruct.subData);
652
+ _position.strategyData.decoded.triggerData = triggerData;
653
+ _position.strategyData.decoded.subData = subData;
654
+ _position.positionId = (0, utils_1.getPositionId)(_position.chainId, _position.protocol.id, _position.owner, subData.troveId, subData.market);
655
+ // User can have:
656
+ // - Only TakeProfit
657
+ // - Only StopLoss
658
+ // - Both
659
+ // TODO: see on frontend what specific data we need here because stop-loss and take-profit is one bundle now
660
+ _position.strategy.strategyId = enums_1.Strategies.Identifiers.CloseOnPrice;
661
+ _position.specific = {};
662
+ return _position;
663
+ }
645
664
  const parsingMethodsMapping = {
646
665
  [enums_1.ProtocolIdentifiers.StrategiesAutomation.MakerDAO]: {
647
666
  [enums_1.Strategies.Identifiers.SavingsLiqProtection]: parseMakerSavingsLiqProtection,
@@ -665,6 +684,7 @@ const parsingMethodsMapping = {
665
684
  [enums_1.ProtocolIdentifiers.StrategiesAutomation.LiquityV2]: {
666
685
  [enums_1.Strategies.Identifiers.Repay]: parseLiquityV2LeverageManagement,
667
686
  [enums_1.Strategies.Identifiers.Boost]: parseLiquityV2LeverageManagement,
687
+ [enums_1.Strategies.Identifiers.CloseOnPrice]: parseLiquityV2CloseOnPrice,
668
688
  },
669
689
  [enums_1.ProtocolIdentifiers.StrategiesAutomation.AaveV2]: {
670
690
  [enums_1.Strategies.Identifiers.Repay]: parseAaveV2LeverageManagement,
@@ -1,5 +1,5 @@
1
1
  import type { OrderType } from '../types/enums';
2
- import { Bundles, ChainId, RatioState, Strategies } from '../types/enums';
2
+ import { CloseToAssetType, Bundles, ChainId, RatioState, Strategies } from '../types/enums';
3
3
  import type { EthereumAddress, StrategyOrBundleIds } from '../types';
4
4
  export declare const makerEncode: {
5
5
  repayFromSavings(bundleId: StrategyOrBundleIds, vaultId: number, triggerRepayRatio: number, targetRepayRatio: number, isBundle?: boolean, chainId?: ChainId, daiAddr?: EthereumAddress, mcdCdpManagerAddr?: EthereumAddress): (boolean | string[] | Strategies.MainnetIds | Strategies.OptimismIds | Strategies.ArbitrumIds | Strategies.BaseIds | Bundles.MainnetIds | Bundles.OptimismIds | Bundles.ArbitrumIds | Bundles.BaseIds)[];
@@ -100,4 +100,5 @@ export declare const morphoBlueEncode: {
100
100
  };
101
101
  export declare const liquityV2Encode: {
102
102
  leverageManagement(market: EthereumAddress, troveId: string, ratioState: RatioState, targetRatio: number, triggerRatio: number, strategyOrBundleId: number): (number | boolean | string[])[];
103
+ closeOnPrice(strategyOrBundleId: number, market: EthereumAddress, troveId: string, collToken: EthereumAddress, boldToken: EthereumAddress, stopLossPrice?: number, stopLossType?: CloseToAssetType, takeProfitPrice?: number, takeProfitType?: CloseToAssetType): (number | boolean | string[])[];
103
104
  };
@@ -274,4 +274,13 @@ exports.liquityV2Encode = {
274
274
  // : Bundles.MainnetIds.LIQUITY_V2_REPAY;
275
275
  return [strategyOrBundleId, isBundle, triggerData, subData];
276
276
  },
277
+ closeOnPrice(strategyOrBundleId, market, troveId, collToken, boldToken, stopLossPrice = 0, stopLossType = enums_1.CloseToAssetType.DEBT, takeProfitPrice = 0, takeProfitType = enums_1.CloseToAssetType.COLLATERAL) {
278
+ const isBundle = true;
279
+ const closeType = (0, utils_1.getCloseStrategyType)(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType);
280
+ const subData = subDataService.liquityV2CloseSubData.encode(market, troveId, collToken, boldToken, closeType);
281
+ const triggerData = triggerService.shouldClosePriceTrigger.encode(collToken, stopLossPrice, takeProfitPrice);
282
+ // TODO: we can hardcode bundleID after testing
283
+ // Bundles.MainnetIds.LIQUITY_V2_CLOSE;
284
+ return [strategyOrBundleId, isBundle, triggerData, subData];
285
+ },
277
286
  };
@@ -1,5 +1,5 @@
1
1
  import type { EthereumAddress } from '../types';
2
- import type { OrderType } from '../types/enums';
2
+ import type { CloseStrategyType, OrderType } from '../types/enums';
3
3
  import { ChainId, RatioState } from '../types/enums';
4
4
  export declare const makerRepayFromSavingsSubData: {
5
5
  encode(vaultId: number, targetRatioPercentage: number, chainId: ChainId, daiAddr?: EthereumAddress, mcdCdpManagerAddr?: EthereumAddress): string[];
@@ -199,3 +199,13 @@ export declare const liquityV2LeverageManagementSubData: {
199
199
  targetRatio: number;
200
200
  };
201
201
  };
202
+ export declare const liquityV2CloseSubData: {
203
+ encode(market: EthereumAddress, troveId: string, collToken: EthereumAddress, boldToken: EthereumAddress, closeType: CloseStrategyType): string[];
204
+ decode(subData: string[]): {
205
+ market: EthereumAddress;
206
+ troveId: string;
207
+ collToken: EthereumAddress;
208
+ boldToken: EthereumAddress;
209
+ closeType: CloseStrategyType;
210
+ };
211
+ };
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.liquityV2LeverageManagementSubData = exports.aaveV3OpenOrderSubData = exports.morphoBlueLeverageManagementSubData = exports.crvUSDPaybackSubData = exports.crvUSDLeverageManagementSubData = exports.liquityDebtInFrontRepaySubData = exports.liquityDsrSupplySubData = exports.liquityDsrPaybackSubData = exports.sparkQuotePriceSubData = exports.sparkLeverageManagementSubData = exports.exchangeLimitOrderSubData = exports.exchangeDcaSubData = exports.liquityPaybackUsingChickenBondSubData = exports.cBondsRebondSubData = exports.morphoAaveV2LeverageManagementSubData = exports.compoundV3L2LeverageManagementSubData = exports.compoundV3LeverageManagementSubData = exports.compoundV2LeverageManagementSubData = exports.aaveV3QuotePriceSubData = exports.aaveV3LeverageManagementSubData = exports.aaveV2LeverageManagementSubData = exports.liquityCloseSubData = exports.liquityLeverageManagementSubData = exports.makerLeverageManagementSubData = exports.makerCloseSubData = exports.liquityRepayFromSavingsSubData = exports.makerRepayFromSavingsSubData = void 0;
6
+ exports.liquityV2CloseSubData = exports.liquityV2LeverageManagementSubData = exports.aaveV3OpenOrderSubData = exports.morphoBlueLeverageManagementSubData = exports.crvUSDPaybackSubData = exports.crvUSDLeverageManagementSubData = exports.liquityDebtInFrontRepaySubData = exports.liquityDsrSupplySubData = exports.liquityDsrPaybackSubData = exports.sparkQuotePriceSubData = exports.sparkLeverageManagementSubData = exports.exchangeLimitOrderSubData = exports.exchangeDcaSubData = exports.liquityPaybackUsingChickenBondSubData = exports.cBondsRebondSubData = exports.morphoAaveV2LeverageManagementSubData = exports.compoundV3L2LeverageManagementSubData = exports.compoundV3LeverageManagementSubData = exports.compoundV2LeverageManagementSubData = exports.aaveV3QuotePriceSubData = exports.aaveV3LeverageManagementSubData = exports.aaveV2LeverageManagementSubData = exports.liquityCloseSubData = exports.liquityLeverageManagementSubData = exports.makerLeverageManagementSubData = exports.makerCloseSubData = exports.liquityRepayFromSavingsSubData = exports.makerRepayFromSavingsSubData = void 0;
7
7
  const decimal_js_1 = __importDefault(require("decimal.js"));
8
8
  const web3_eth_abi_1 = __importDefault(require("web3-eth-abi"));
9
9
  const web3_utils_1 = require("web3-utils");
@@ -497,3 +497,33 @@ exports.liquityV2LeverageManagementSubData = {
497
497
  };
498
498
  },
499
499
  };
500
+ exports.liquityV2CloseSubData = {
501
+ encode(market, troveId, collToken, boldToken, closeType) {
502
+ const marketEncoded = web3_eth_abi_1.default.encodeParameter('address', market);
503
+ const troveIdEncoded = web3_eth_abi_1.default.encodeParameter('uint256', troveId);
504
+ const collAddrEncoded = web3_eth_abi_1.default.encodeParameter('address', collToken);
505
+ const boldTokenEncoded = web3_eth_abi_1.default.encodeParameter('address', boldToken);
506
+ const wethAddress = (0, tokens_1.getAssetInfo)('WETH').address;
507
+ const wethAddressEncoded = web3_eth_abi_1.default.encodeParameter('address', wethAddress);
508
+ const closeTypeEncoded = web3_eth_abi_1.default.encodeParameter('uint8', closeType);
509
+ return [
510
+ marketEncoded,
511
+ troveIdEncoded,
512
+ collAddrEncoded,
513
+ boldTokenEncoded,
514
+ wethAddressEncoded,
515
+ closeTypeEncoded,
516
+ ];
517
+ },
518
+ decode(subData) {
519
+ const market = web3_eth_abi_1.default.decodeParameter('address', subData[0]);
520
+ const troveId = web3_eth_abi_1.default.decodeParameter('uint256', subData[1]);
521
+ const collToken = web3_eth_abi_1.default.decodeParameter('address', subData[2]);
522
+ const boldToken = web3_eth_abi_1.default.decodeParameter('address', subData[3]);
523
+ // skip wethAddress
524
+ const closeType = web3_eth_abi_1.default.decodeParameter('uint8', subData[5]);
525
+ return {
526
+ market, troveId, collToken, boldToken, closeType,
527
+ };
528
+ },
529
+ };
@@ -198,3 +198,11 @@ export declare const liquityV2RatioTrigger: {
198
198
  ratioState: number;
199
199
  };
200
200
  };
201
+ export declare const shouldClosePriceTrigger: {
202
+ encode(tokenAddr: EthereumAddress, lowerPrice: number, upperPrice: number): string[];
203
+ decode(triggerData: string[]): {
204
+ tokenAddr: EthereumAddress;
205
+ lowerPrice: string;
206
+ upperPrice: string;
207
+ };
208
+ };
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.liquityV2RatioTrigger = exports.morphoBlueRatioTrigger = exports.crvUsdHealthRatioTrigger = exports.crvUSDRatioTrigger = exports.curveUsdSoftLiquidationTrigger = exports.curveUsdBorrowRateTrigger = exports.sparkQuotePriceTrigger = exports.sparkRatioTrigger = exports.exchangeOffchainPriceTrigger = exports.exchangeTimestampTrigger = exports.compoundV3RatioTrigger = exports.cBondsRebondTrigger = exports.aaveV2RatioTrigger = exports.liquityDebtInFrontWithLimitTrigger = exports.liquityDebtInFrontTrigger = exports.liquityRatioTrigger = exports.compoundV2RatioTrigger = exports.aaveV3QuotePriceWithMaximumGasPriceTrigger = exports.aaveV3QuotePriceTrigger = exports.morphoAaveV2RatioTrigger = exports.aaveV3RatioTrigger = exports.makerRatioTrigger = exports.trailingStopTrigger = exports.chainlinkPriceTrigger = void 0;
29
+ exports.shouldClosePriceTrigger = exports.liquityV2RatioTrigger = exports.morphoBlueRatioTrigger = exports.crvUsdHealthRatioTrigger = exports.crvUSDRatioTrigger = exports.curveUsdSoftLiquidationTrigger = exports.curveUsdBorrowRateTrigger = exports.sparkQuotePriceTrigger = exports.sparkRatioTrigger = exports.exchangeOffchainPriceTrigger = exports.exchangeTimestampTrigger = exports.compoundV3RatioTrigger = exports.cBondsRebondTrigger = exports.aaveV2RatioTrigger = exports.liquityDebtInFrontWithLimitTrigger = exports.liquityDebtInFrontTrigger = exports.liquityRatioTrigger = exports.compoundV2RatioTrigger = exports.aaveV3QuotePriceWithMaximumGasPriceTrigger = exports.aaveV3QuotePriceTrigger = exports.morphoAaveV2RatioTrigger = exports.aaveV3RatioTrigger = exports.makerRatioTrigger = exports.trailingStopTrigger = exports.chainlinkPriceTrigger = void 0;
30
30
  const decimal_js_1 = __importDefault(require("decimal.js"));
31
31
  const tokens_1 = require("@defisaver/tokens");
32
32
  const web3_eth_abi_1 = __importDefault(require("web3-eth-abi"));
@@ -380,3 +380,20 @@ exports.liquityV2RatioTrigger = {
380
380
  };
381
381
  },
382
382
  };
383
+ exports.shouldClosePriceTrigger = {
384
+ encode(tokenAddr, lowerPrice, upperPrice) {
385
+ const lowerPriceFormatted = new decimal_js_1.default(lowerPrice).mul(1e8).floor().toString();
386
+ const upperPriceFormatted = new decimal_js_1.default(upperPrice).mul(1e8).floor().toString();
387
+ return [
388
+ web3_eth_abi_1.default.encodeParameters(['address', 'uint256', 'uint256'], [tokenAddr, lowerPriceFormatted, upperPriceFormatted]),
389
+ ];
390
+ },
391
+ decode(triggerData) {
392
+ const decodedData = web3_eth_abi_1.default.decodeParameters(['address', 'uint256', 'uint256'], triggerData[0]);
393
+ return {
394
+ tokenAddr: decodedData[0],
395
+ lowerPrice: new decimal_js_1.default(decodedData[1]).div(1e8).toString(),
396
+ upperPrice: new decimal_js_1.default(decodedData[2]).div(1e8).toString(),
397
+ };
398
+ },
399
+ };
@@ -1,5 +1,5 @@
1
1
  import type { EthereumAddress } from '../types';
2
- import { ChainId, RatioState } from '../types/enums';
2
+ import { ChainId, CloseStrategyType, CloseToAssetType, RatioState } from '../types/enums';
3
3
  export declare function isDefined<T>(value: T): value is NonNullable<T>;
4
4
  export declare function isUndefined(value: unknown): boolean;
5
5
  export declare function compareAddresses(firstAddress: EthereumAddress, secondAddress: EthereumAddress): boolean;
@@ -23,3 +23,4 @@ export declare function getRatioStateInfoForAaveCloseStrategy(currentRatioState:
23
23
  ratioState: RatioState;
24
24
  };
25
25
  export declare function getPositionId(...args: (number | string)[]): string;
26
+ export declare function getCloseStrategyType(stopLossPrice: number, stopLossType: CloseToAssetType, takeProfitPrice: number, takeProfitType: CloseToAssetType): CloseStrategyType;
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.getPositionId = exports.getRatioStateInfoForAaveCloseStrategy = exports.requireAddresses = exports.requireAddress = exports.isEmptyBytes = exports.isRatioStateUnder = exports.isRatioStateOver = exports.weiToRatioPercentage = exports.ratioPercentageToWei = exports.encodeSubId = exports.compareSubHashes = exports.wethToEthByAddress = exports.wethToEth = exports.ethToWeth = exports.addToObjectIf = exports.addToArrayIf = exports.isAddress = exports.compareAddresses = exports.isUndefined = exports.isDefined = void 0;
29
+ exports.getCloseStrategyType = exports.getPositionId = exports.getRatioStateInfoForAaveCloseStrategy = exports.requireAddresses = exports.requireAddress = exports.isEmptyBytes = exports.isRatioStateUnder = exports.isRatioStateOver = exports.weiToRatioPercentage = exports.ratioPercentageToWei = exports.encodeSubId = exports.compareSubHashes = exports.wethToEthByAddress = exports.wethToEth = exports.ethToWeth = exports.addToObjectIf = exports.addToArrayIf = exports.isAddress = exports.compareAddresses = exports.isUndefined = exports.isDefined = void 0;
30
30
  const decimal_js_1 = __importDefault(require("decimal.js"));
31
31
  const web3Utils = __importStar(require("web3-utils"));
32
32
  const web3_eth_abi_1 = __importDefault(require("web3-eth-abi"));
@@ -129,3 +129,31 @@ function getPositionId(...args) {
129
129
  return args.map(arg => arg.toString().toLowerCase().split(' ').join('_')).join('-');
130
130
  }
131
131
  exports.getPositionId = getPositionId;
132
+ function getCloseStrategyType(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType) {
133
+ const isStopLoss = stopLossPrice > 0;
134
+ const isTakeProfit = takeProfitPrice > 0;
135
+ if (!isStopLoss && !isTakeProfit) {
136
+ throw new Error('CloseOnPrice: At least one price must be defined');
137
+ }
138
+ if (isStopLoss && isTakeProfit) {
139
+ if (stopLossType === enums_1.CloseToAssetType.COLLATERAL && takeProfitType === enums_1.CloseToAssetType.COLLATERAL) {
140
+ return enums_1.CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL;
141
+ }
142
+ if (stopLossType === enums_1.CloseToAssetType.COLLATERAL) {
143
+ return enums_1.CloseStrategyType.TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL;
144
+ }
145
+ if (takeProfitType === enums_1.CloseToAssetType.COLLATERAL) {
146
+ return enums_1.CloseStrategyType.TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT;
147
+ }
148
+ return enums_1.CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT;
149
+ }
150
+ if (isStopLoss) {
151
+ return stopLossType === enums_1.CloseToAssetType.COLLATERAL
152
+ ? enums_1.CloseStrategyType.STOP_LOSS_IN_COLLATERAL
153
+ : enums_1.CloseStrategyType.STOP_LOSS_IN_DEBT;
154
+ }
155
+ return takeProfitType === enums_1.CloseToAssetType.COLLATERAL
156
+ ? enums_1.CloseStrategyType.TAKE_PROFIT_IN_COLLATERAL
157
+ : enums_1.CloseStrategyType.TAKE_PROFIT_IN_DEBT;
158
+ }
159
+ exports.getCloseStrategyType = getCloseStrategyType;
@@ -25,6 +25,20 @@ export declare enum DebtActionType {
25
25
  PAYBACK = 0,
26
26
  BORROW = 1
27
27
  }
28
+ export declare enum CloseStrategyType {
29
+ TAKE_PROFIT_IN_COLLATERAL = 0,
30
+ STOP_LOSS_IN_COLLATERAL = 1,
31
+ TAKE_PROFIT_IN_DEBT = 2,
32
+ STOP_LOSS_IN_DEBT = 3,
33
+ TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL = 4,
34
+ TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT = 5,
35
+ TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT = 6,
36
+ TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL = 7
37
+ }
38
+ export declare enum CloseToAssetType {
39
+ COLLATERAL = 0,
40
+ DEBT = 1
41
+ }
28
42
  /**
29
43
  * @dev Follow the naming convention:
30
44
  * - Enum name consists of two parts, name and version
@@ -100,6 +114,7 @@ export declare namespace Strategies {
100
114
  CloseToCollateralWithGasPrice = "close-to-collateral-with-gas-price",
101
115
  CloseOnPriceToDebt = "close-on-price-to-debt",
102
116
  CloseOnPriceToColl = "close-on-price-to-collateral",
117
+ CloseOnPrice = "close-on-price",
103
118
  TrailingStopToColl = "trailing-stop-to-collateral",
104
119
  TrailingStopToDebt = "trailing-stop-to-debt",
105
120
  Rebond = "rebond",
@@ -163,7 +178,8 @@ export declare namespace Bundles {
163
178
  MORPHO_BLUE_EOA_BOOST = 35,
164
179
  AAVE_V3_OPEN_ORDER_FROM_COLLATERAL = 36,
165
180
  LIQUITY_V2_REPAY = 37,
166
- LIQUITY_V2_BOOST = 38
181
+ LIQUITY_V2_BOOST = 38,
182
+ LIQUITY_V2_CLOSE = 39
167
183
  }
168
184
  enum OptimismIds {
169
185
  AAVE_V3_REPAY = 0,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Bundles = exports.Strategies = exports.ProtocolIdentifiers = exports.DebtActionType = exports.CollActionType = exports.BundleProtocols = exports.OrderType = exports.RatioState = exports.ChainId = void 0;
3
+ exports.Bundles = exports.Strategies = exports.ProtocolIdentifiers = exports.CloseToAssetType = exports.CloseStrategyType = exports.DebtActionType = exports.CollActionType = exports.BundleProtocols = exports.OrderType = exports.RatioState = exports.ChainId = void 0;
4
4
  var ChainId;
5
5
  (function (ChainId) {
6
6
  ChainId[ChainId["Ethereum"] = 1] = "Ethereum";
@@ -34,6 +34,22 @@ var DebtActionType;
34
34
  DebtActionType[DebtActionType["PAYBACK"] = 0] = "PAYBACK";
35
35
  DebtActionType[DebtActionType["BORROW"] = 1] = "BORROW";
36
36
  })(DebtActionType = exports.DebtActionType || (exports.DebtActionType = {}));
37
+ var CloseStrategyType;
38
+ (function (CloseStrategyType) {
39
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_COLLATERAL"] = 0] = "TAKE_PROFIT_IN_COLLATERAL";
40
+ CloseStrategyType[CloseStrategyType["STOP_LOSS_IN_COLLATERAL"] = 1] = "STOP_LOSS_IN_COLLATERAL";
41
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_DEBT"] = 2] = "TAKE_PROFIT_IN_DEBT";
42
+ CloseStrategyType[CloseStrategyType["STOP_LOSS_IN_DEBT"] = 3] = "STOP_LOSS_IN_DEBT";
43
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL"] = 4] = "TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL";
44
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT"] = 5] = "TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT";
45
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT"] = 6] = "TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT";
46
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL"] = 7] = "TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL";
47
+ })(CloseStrategyType = exports.CloseStrategyType || (exports.CloseStrategyType = {}));
48
+ var CloseToAssetType;
49
+ (function (CloseToAssetType) {
50
+ CloseToAssetType[CloseToAssetType["COLLATERAL"] = 0] = "COLLATERAL";
51
+ CloseToAssetType[CloseToAssetType["DEBT"] = 1] = "DEBT";
52
+ })(CloseToAssetType = exports.CloseToAssetType || (exports.CloseToAssetType = {}));
37
53
  /**
38
54
  * @dev Follow the naming convention:
39
55
  * - Enum name consists of two parts, name and version
@@ -118,6 +134,7 @@ var Strategies;
118
134
  Identifiers["CloseToCollateralWithGasPrice"] = "close-to-collateral-with-gas-price";
119
135
  Identifiers["CloseOnPriceToDebt"] = "close-on-price-to-debt";
120
136
  Identifiers["CloseOnPriceToColl"] = "close-on-price-to-collateral";
137
+ Identifiers["CloseOnPrice"] = "close-on-price";
121
138
  Identifiers["TrailingStopToColl"] = "trailing-stop-to-collateral";
122
139
  Identifiers["TrailingStopToDebt"] = "trailing-stop-to-debt";
123
140
  Identifiers["Rebond"] = "rebond";
@@ -185,6 +202,7 @@ var Bundles;
185
202
  MainnetIds[MainnetIds["AAVE_V3_OPEN_ORDER_FROM_COLLATERAL"] = 36] = "AAVE_V3_OPEN_ORDER_FROM_COLLATERAL";
186
203
  MainnetIds[MainnetIds["LIQUITY_V2_REPAY"] = 37] = "LIQUITY_V2_REPAY";
187
204
  MainnetIds[MainnetIds["LIQUITY_V2_BOOST"] = 38] = "LIQUITY_V2_BOOST";
205
+ MainnetIds[MainnetIds["LIQUITY_V2_CLOSE"] = 39] = "LIQUITY_V2_CLOSE";
188
206
  })(MainnetIds = Bundles.MainnetIds || (Bundles.MainnetIds = {}));
189
207
  let OptimismIds;
190
208
  (function (OptimismIds) {
@@ -367,6 +367,11 @@ export const MAINNET_BUNDLES_INFO = {
367
367
  strategyId: Strategies.Identifiers.Boost,
368
368
  protocol: PROTOCOLS.LiquityV2,
369
369
  },
370
+ [Bundles.MainnetIds.LIQUITY_V2_CLOSE]: {
371
+ strategyOrBundleId: Bundles.MainnetIds.LIQUITY_V2_CLOSE,
372
+ strategyId: Strategies.Identifiers.CloseOnPrice,
373
+ protocol: PROTOCOLS.LiquityV2,
374
+ },
370
375
  };
371
376
  export const OPTIMISM_BUNDLES_INFO = {
372
377
  [Bundles.OptimismIds.AAVE_V3_REPAY]: {
@@ -405,7 +405,7 @@ function parseLiquityLeverageManagement(position, parseData) {
405
405
  }
406
406
  function parseLiquityV2LeverageManagement(position, parseData) {
407
407
  const _position = cloneDeep(position);
408
- const { subStruct, subId } = parseData.subscriptionEventData;
408
+ const { subStruct, subId, subHash } = parseData.subscriptionEventData;
409
409
  const { isEnabled } = parseData.strategiesSubsData;
410
410
  const triggerData = triggerService.liquityV2RatioTrigger.decode(subStruct.triggerData);
411
411
  const subData = subDataService.liquityV2LeverageManagementSubData.decode(subStruct.subData);
@@ -417,8 +417,9 @@ function parseLiquityV2LeverageManagement(position, parseData) {
417
417
  _position.specific = {
418
418
  triggerRepayRatio: triggerData.ratio,
419
419
  targetRepayRatio: subData.targetRatio,
420
- repayEnabled: true,
420
+ repayEnabled: isEnabled,
421
421
  subId1: Number(subId),
422
+ subHashRepay: subHash,
422
423
  mergeWithId: Strategies.Identifiers.Boost,
423
424
  };
424
425
  }
@@ -428,6 +429,7 @@ function parseLiquityV2LeverageManagement(position, parseData) {
428
429
  targetBoostRatio: subData.targetRatio,
429
430
  boostEnabled: isEnabled,
430
431
  subId2: Number(subId),
432
+ subHashBoost: subHash,
431
433
  mergeId: Strategies.Identifiers.Boost,
432
434
  };
433
435
  }
@@ -616,6 +618,23 @@ function parseAaveV3OpenOrderFromCollateral(position, parseData) {
616
618
  };
617
619
  return _position;
618
620
  }
621
+ function parseLiquityV2CloseOnPrice(position, parseData) {
622
+ const _position = cloneDeep(position);
623
+ const { subStruct } = parseData.subscriptionEventData;
624
+ const triggerData = triggerService.shouldClosePriceTrigger.decode(subStruct.triggerData);
625
+ const subData = subDataService.liquityV2CloseSubData.decode(subStruct.subData);
626
+ _position.strategyData.decoded.triggerData = triggerData;
627
+ _position.strategyData.decoded.subData = subData;
628
+ _position.positionId = getPositionId(_position.chainId, _position.protocol.id, _position.owner, subData.troveId, subData.market);
629
+ // User can have:
630
+ // - Only TakeProfit
631
+ // - Only StopLoss
632
+ // - Both
633
+ // TODO: see on frontend what specific data we need here because stop-loss and take-profit is one bundle now
634
+ _position.strategy.strategyId = Strategies.Identifiers.CloseOnPrice;
635
+ _position.specific = {};
636
+ return _position;
637
+ }
619
638
  const parsingMethodsMapping = {
620
639
  [ProtocolIdentifiers.StrategiesAutomation.MakerDAO]: {
621
640
  [Strategies.Identifiers.SavingsLiqProtection]: parseMakerSavingsLiqProtection,
@@ -639,6 +658,7 @@ const parsingMethodsMapping = {
639
658
  [ProtocolIdentifiers.StrategiesAutomation.LiquityV2]: {
640
659
  [Strategies.Identifiers.Repay]: parseLiquityV2LeverageManagement,
641
660
  [Strategies.Identifiers.Boost]: parseLiquityV2LeverageManagement,
661
+ [Strategies.Identifiers.CloseOnPrice]: parseLiquityV2CloseOnPrice,
642
662
  },
643
663
  [ProtocolIdentifiers.StrategiesAutomation.AaveV2]: {
644
664
  [Strategies.Identifiers.Repay]: parseAaveV2LeverageManagement,
@@ -1,5 +1,5 @@
1
1
  import type { OrderType } from '../types/enums';
2
- import { Bundles, ChainId, RatioState, Strategies } from '../types/enums';
2
+ import { CloseToAssetType, Bundles, ChainId, RatioState, Strategies } from '../types/enums';
3
3
  import type { EthereumAddress, StrategyOrBundleIds } from '../types';
4
4
  export declare const makerEncode: {
5
5
  repayFromSavings(bundleId: StrategyOrBundleIds, vaultId: number, triggerRepayRatio: number, targetRepayRatio: number, isBundle?: boolean, chainId?: ChainId, daiAddr?: EthereumAddress, mcdCdpManagerAddr?: EthereumAddress): (boolean | string[] | Strategies.MainnetIds | Strategies.OptimismIds | Strategies.ArbitrumIds | Strategies.BaseIds | Bundles.MainnetIds | Bundles.OptimismIds | Bundles.ArbitrumIds | Bundles.BaseIds)[];
@@ -100,4 +100,5 @@ export declare const morphoBlueEncode: {
100
100
  };
101
101
  export declare const liquityV2Encode: {
102
102
  leverageManagement(market: EthereumAddress, troveId: string, ratioState: RatioState, targetRatio: number, triggerRatio: number, strategyOrBundleId: number): (number | boolean | string[])[];
103
+ closeOnPrice(strategyOrBundleId: number, market: EthereumAddress, troveId: string, collToken: EthereumAddress, boldToken: EthereumAddress, stopLossPrice?: number, stopLossType?: CloseToAssetType, takeProfitPrice?: number, takeProfitType?: CloseToAssetType): (number | boolean | string[])[];
103
104
  };
@@ -1,10 +1,10 @@
1
1
  import Dec from 'decimal.js';
2
2
  import { getAssetInfo } from '@defisaver/tokens';
3
- import { Bundles, ChainId, RatioState, Strategies, } from '../types/enums';
3
+ import { CloseToAssetType, Bundles, ChainId, RatioState, Strategies, } from '../types/enums';
4
4
  import { STRATEGY_IDS } from '../constants';
5
5
  import * as subDataService from './subDataService';
6
6
  import * as triggerService from './triggerService';
7
- import { compareAddresses, requireAddress, requireAddresses } from './utils';
7
+ import { compareAddresses, getCloseStrategyType, requireAddress, requireAddresses, } from './utils';
8
8
  export const makerEncode = {
9
9
  repayFromSavings(bundleId, vaultId, triggerRepayRatio, targetRepayRatio, isBundle = true, chainId = ChainId.Ethereum, daiAddr, mcdCdpManagerAddr) {
10
10
  const subData = subDataService.makerRepayFromSavingsSubData.encode(vaultId, targetRepayRatio, chainId, daiAddr, mcdCdpManagerAddr);
@@ -245,4 +245,13 @@ export const liquityV2Encode = {
245
245
  // : Bundles.MainnetIds.LIQUITY_V2_REPAY;
246
246
  return [strategyOrBundleId, isBundle, triggerData, subData];
247
247
  },
248
+ closeOnPrice(strategyOrBundleId, market, troveId, collToken, boldToken, stopLossPrice = 0, stopLossType = CloseToAssetType.DEBT, takeProfitPrice = 0, takeProfitType = CloseToAssetType.COLLATERAL) {
249
+ const isBundle = true;
250
+ const closeType = getCloseStrategyType(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType);
251
+ const subData = subDataService.liquityV2CloseSubData.encode(market, troveId, collToken, boldToken, closeType);
252
+ const triggerData = triggerService.shouldClosePriceTrigger.encode(collToken, stopLossPrice, takeProfitPrice);
253
+ // TODO: we can hardcode bundleID after testing
254
+ // Bundles.MainnetIds.LIQUITY_V2_CLOSE;
255
+ return [strategyOrBundleId, isBundle, triggerData, subData];
256
+ },
248
257
  };
@@ -1,5 +1,5 @@
1
1
  import type { EthereumAddress } from '../types';
2
- import type { OrderType } from '../types/enums';
2
+ import type { CloseStrategyType, OrderType } from '../types/enums';
3
3
  import { ChainId, RatioState } from '../types/enums';
4
4
  export declare const makerRepayFromSavingsSubData: {
5
5
  encode(vaultId: number, targetRatioPercentage: number, chainId: ChainId, daiAddr?: EthereumAddress, mcdCdpManagerAddr?: EthereumAddress): string[];
@@ -199,3 +199,13 @@ export declare const liquityV2LeverageManagementSubData: {
199
199
  targetRatio: number;
200
200
  };
201
201
  };
202
+ export declare const liquityV2CloseSubData: {
203
+ encode(market: EthereumAddress, troveId: string, collToken: EthereumAddress, boldToken: EthereumAddress, closeType: CloseStrategyType): string[];
204
+ decode(subData: string[]): {
205
+ market: EthereumAddress;
206
+ troveId: string;
207
+ collToken: EthereumAddress;
208
+ boldToken: EthereumAddress;
209
+ closeType: CloseStrategyType;
210
+ };
211
+ };
@@ -491,3 +491,33 @@ export const liquityV2LeverageManagementSubData = {
491
491
  };
492
492
  },
493
493
  };
494
+ export const liquityV2CloseSubData = {
495
+ encode(market, troveId, collToken, boldToken, closeType) {
496
+ const marketEncoded = AbiCoder.encodeParameter('address', market);
497
+ const troveIdEncoded = AbiCoder.encodeParameter('uint256', troveId);
498
+ const collAddrEncoded = AbiCoder.encodeParameter('address', collToken);
499
+ const boldTokenEncoded = AbiCoder.encodeParameter('address', boldToken);
500
+ const wethAddress = getAssetInfo('WETH').address;
501
+ const wethAddressEncoded = AbiCoder.encodeParameter('address', wethAddress);
502
+ const closeTypeEncoded = AbiCoder.encodeParameter('uint8', closeType);
503
+ return [
504
+ marketEncoded,
505
+ troveIdEncoded,
506
+ collAddrEncoded,
507
+ boldTokenEncoded,
508
+ wethAddressEncoded,
509
+ closeTypeEncoded,
510
+ ];
511
+ },
512
+ decode(subData) {
513
+ const market = AbiCoder.decodeParameter('address', subData[0]);
514
+ const troveId = AbiCoder.decodeParameter('uint256', subData[1]);
515
+ const collToken = AbiCoder.decodeParameter('address', subData[2]);
516
+ const boldToken = AbiCoder.decodeParameter('address', subData[3]);
517
+ // skip wethAddress
518
+ const closeType = AbiCoder.decodeParameter('uint8', subData[5]);
519
+ return {
520
+ market, troveId, collToken, boldToken, closeType,
521
+ };
522
+ },
523
+ };
@@ -198,3 +198,11 @@ export declare const liquityV2RatioTrigger: {
198
198
  ratioState: number;
199
199
  };
200
200
  };
201
+ export declare const shouldClosePriceTrigger: {
202
+ encode(tokenAddr: EthereumAddress, lowerPrice: number, upperPrice: number): string[];
203
+ decode(triggerData: string[]): {
204
+ tokenAddr: EthereumAddress;
205
+ lowerPrice: string;
206
+ upperPrice: string;
207
+ };
208
+ };
@@ -351,3 +351,20 @@ export const liquityV2RatioTrigger = {
351
351
  };
352
352
  },
353
353
  };
354
+ export const shouldClosePriceTrigger = {
355
+ encode(tokenAddr, lowerPrice, upperPrice) {
356
+ const lowerPriceFormatted = new Dec(lowerPrice).mul(1e8).floor().toString();
357
+ const upperPriceFormatted = new Dec(upperPrice).mul(1e8).floor().toString();
358
+ return [
359
+ AbiCoder.encodeParameters(['address', 'uint256', 'uint256'], [tokenAddr, lowerPriceFormatted, upperPriceFormatted]),
360
+ ];
361
+ },
362
+ decode(triggerData) {
363
+ const decodedData = AbiCoder.decodeParameters(['address', 'uint256', 'uint256'], triggerData[0]);
364
+ return {
365
+ tokenAddr: decodedData[0],
366
+ lowerPrice: new Dec(decodedData[1]).div(1e8).toString(),
367
+ upperPrice: new Dec(decodedData[2]).div(1e8).toString(),
368
+ };
369
+ },
370
+ };
@@ -1,5 +1,5 @@
1
1
  import type { EthereumAddress } from '../types';
2
- import { ChainId, RatioState } from '../types/enums';
2
+ import { ChainId, CloseStrategyType, CloseToAssetType, RatioState } from '../types/enums';
3
3
  export declare function isDefined<T>(value: T): value is NonNullable<T>;
4
4
  export declare function isUndefined(value: unknown): boolean;
5
5
  export declare function compareAddresses(firstAddress: EthereumAddress, secondAddress: EthereumAddress): boolean;
@@ -23,3 +23,4 @@ export declare function getRatioStateInfoForAaveCloseStrategy(currentRatioState:
23
23
  ratioState: RatioState;
24
24
  };
25
25
  export declare function getPositionId(...args: (number | string)[]): string;
26
+ export declare function getCloseStrategyType(stopLossPrice: number, stopLossType: CloseToAssetType, takeProfitPrice: number, takeProfitType: CloseToAssetType): CloseStrategyType;
@@ -2,7 +2,7 @@ import Dec from 'decimal.js';
2
2
  import * as web3Utils from 'web3-utils';
3
3
  import AbiCoder from 'web3-eth-abi';
4
4
  import { getAssetInfo, getAssetInfoByAddress } from '@defisaver/tokens';
5
- import { ChainId, RatioState } from '../types/enums';
5
+ import { ChainId, CloseStrategyType, CloseToAssetType, RatioState, } from '../types/enums';
6
6
  export function isDefined(value) {
7
7
  return value !== undefined && value !== null;
8
8
  }
@@ -80,3 +80,30 @@ export function getRatioStateInfoForAaveCloseStrategy(currentRatioState, collAss
80
80
  export function getPositionId(...args) {
81
81
  return args.map(arg => arg.toString().toLowerCase().split(' ').join('_')).join('-');
82
82
  }
83
+ export function getCloseStrategyType(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType) {
84
+ const isStopLoss = stopLossPrice > 0;
85
+ const isTakeProfit = takeProfitPrice > 0;
86
+ if (!isStopLoss && !isTakeProfit) {
87
+ throw new Error('CloseOnPrice: At least one price must be defined');
88
+ }
89
+ if (isStopLoss && isTakeProfit) {
90
+ if (stopLossType === CloseToAssetType.COLLATERAL && takeProfitType === CloseToAssetType.COLLATERAL) {
91
+ return CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL;
92
+ }
93
+ if (stopLossType === CloseToAssetType.COLLATERAL) {
94
+ return CloseStrategyType.TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL;
95
+ }
96
+ if (takeProfitType === CloseToAssetType.COLLATERAL) {
97
+ return CloseStrategyType.TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT;
98
+ }
99
+ return CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT;
100
+ }
101
+ if (isStopLoss) {
102
+ return stopLossType === CloseToAssetType.COLLATERAL
103
+ ? CloseStrategyType.STOP_LOSS_IN_COLLATERAL
104
+ : CloseStrategyType.STOP_LOSS_IN_DEBT;
105
+ }
106
+ return takeProfitType === CloseToAssetType.COLLATERAL
107
+ ? CloseStrategyType.TAKE_PROFIT_IN_COLLATERAL
108
+ : CloseStrategyType.TAKE_PROFIT_IN_DEBT;
109
+ }
@@ -25,6 +25,20 @@ export declare enum DebtActionType {
25
25
  PAYBACK = 0,
26
26
  BORROW = 1
27
27
  }
28
+ export declare enum CloseStrategyType {
29
+ TAKE_PROFIT_IN_COLLATERAL = 0,
30
+ STOP_LOSS_IN_COLLATERAL = 1,
31
+ TAKE_PROFIT_IN_DEBT = 2,
32
+ STOP_LOSS_IN_DEBT = 3,
33
+ TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL = 4,
34
+ TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT = 5,
35
+ TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT = 6,
36
+ TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL = 7
37
+ }
38
+ export declare enum CloseToAssetType {
39
+ COLLATERAL = 0,
40
+ DEBT = 1
41
+ }
28
42
  /**
29
43
  * @dev Follow the naming convention:
30
44
  * - Enum name consists of two parts, name and version
@@ -100,6 +114,7 @@ export declare namespace Strategies {
100
114
  CloseToCollateralWithGasPrice = "close-to-collateral-with-gas-price",
101
115
  CloseOnPriceToDebt = "close-on-price-to-debt",
102
116
  CloseOnPriceToColl = "close-on-price-to-collateral",
117
+ CloseOnPrice = "close-on-price",
103
118
  TrailingStopToColl = "trailing-stop-to-collateral",
104
119
  TrailingStopToDebt = "trailing-stop-to-debt",
105
120
  Rebond = "rebond",
@@ -163,7 +178,8 @@ export declare namespace Bundles {
163
178
  MORPHO_BLUE_EOA_BOOST = 35,
164
179
  AAVE_V3_OPEN_ORDER_FROM_COLLATERAL = 36,
165
180
  LIQUITY_V2_REPAY = 37,
166
- LIQUITY_V2_BOOST = 38
181
+ LIQUITY_V2_BOOST = 38,
182
+ LIQUITY_V2_CLOSE = 39
167
183
  }
168
184
  enum OptimismIds {
169
185
  AAVE_V3_REPAY = 0,
@@ -31,6 +31,22 @@ export var DebtActionType;
31
31
  DebtActionType[DebtActionType["PAYBACK"] = 0] = "PAYBACK";
32
32
  DebtActionType[DebtActionType["BORROW"] = 1] = "BORROW";
33
33
  })(DebtActionType || (DebtActionType = {}));
34
+ export var CloseStrategyType;
35
+ (function (CloseStrategyType) {
36
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_COLLATERAL"] = 0] = "TAKE_PROFIT_IN_COLLATERAL";
37
+ CloseStrategyType[CloseStrategyType["STOP_LOSS_IN_COLLATERAL"] = 1] = "STOP_LOSS_IN_COLLATERAL";
38
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_DEBT"] = 2] = "TAKE_PROFIT_IN_DEBT";
39
+ CloseStrategyType[CloseStrategyType["STOP_LOSS_IN_DEBT"] = 3] = "STOP_LOSS_IN_DEBT";
40
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL"] = 4] = "TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL";
41
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT"] = 5] = "TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT";
42
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT"] = 6] = "TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT";
43
+ CloseStrategyType[CloseStrategyType["TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL"] = 7] = "TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL";
44
+ })(CloseStrategyType || (CloseStrategyType = {}));
45
+ export var CloseToAssetType;
46
+ (function (CloseToAssetType) {
47
+ CloseToAssetType[CloseToAssetType["COLLATERAL"] = 0] = "COLLATERAL";
48
+ CloseToAssetType[CloseToAssetType["DEBT"] = 1] = "DEBT";
49
+ })(CloseToAssetType || (CloseToAssetType = {}));
34
50
  /**
35
51
  * @dev Follow the naming convention:
36
52
  * - Enum name consists of two parts, name and version
@@ -115,6 +131,7 @@ export var Strategies;
115
131
  Identifiers["CloseToCollateralWithGasPrice"] = "close-to-collateral-with-gas-price";
116
132
  Identifiers["CloseOnPriceToDebt"] = "close-on-price-to-debt";
117
133
  Identifiers["CloseOnPriceToColl"] = "close-on-price-to-collateral";
134
+ Identifiers["CloseOnPrice"] = "close-on-price";
118
135
  Identifiers["TrailingStopToColl"] = "trailing-stop-to-collateral";
119
136
  Identifiers["TrailingStopToDebt"] = "trailing-stop-to-debt";
120
137
  Identifiers["Rebond"] = "rebond";
@@ -182,6 +199,7 @@ export var Bundles;
182
199
  MainnetIds[MainnetIds["AAVE_V3_OPEN_ORDER_FROM_COLLATERAL"] = 36] = "AAVE_V3_OPEN_ORDER_FROM_COLLATERAL";
183
200
  MainnetIds[MainnetIds["LIQUITY_V2_REPAY"] = 37] = "LIQUITY_V2_REPAY";
184
201
  MainnetIds[MainnetIds["LIQUITY_V2_BOOST"] = 38] = "LIQUITY_V2_BOOST";
202
+ MainnetIds[MainnetIds["LIQUITY_V2_CLOSE"] = 39] = "LIQUITY_V2_CLOSE";
185
203
  })(MainnetIds = Bundles.MainnetIds || (Bundles.MainnetIds = {}));
186
204
  let OptimismIds;
187
205
  (function (OptimismIds) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/automation-sdk",
3
- "version": "3.1.1-dev",
3
+ "version": "3.1.1-dev-2",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -385,6 +385,11 @@ export const MAINNET_BUNDLES_INFO: MainnetBundleInfo = {
385
385
  strategyId: Strategies.Identifiers.Boost,
386
386
  protocol: PROTOCOLS.LiquityV2,
387
387
  },
388
+ [Bundles.MainnetIds.LIQUITY_V2_CLOSE]: {
389
+ strategyOrBundleId: Bundles.MainnetIds.LIQUITY_V2_CLOSE,
390
+ strategyId: Strategies.Identifiers.CloseOnPrice,
391
+ protocol: PROTOCOLS.LiquityV2,
392
+ },
388
393
  };
389
394
 
390
395
  export const OPTIMISM_BUNDLES_INFO: OptimismBundleInfo = {
@@ -566,7 +566,7 @@ function parseLiquityLeverageManagement(position: Position.Automated, parseData:
566
566
  function parseLiquityV2LeverageManagement(position: Position.Automated, parseData: ParseData): Position.Automated {
567
567
  const _position = cloneDeep(position);
568
568
 
569
- const { subStruct, subId } = parseData.subscriptionEventData;
569
+ const { subStruct, subId, subHash } = parseData.subscriptionEventData;
570
570
  const { isEnabled } = parseData.strategiesSubsData;
571
571
 
572
572
  const triggerData = triggerService.liquityV2RatioTrigger.decode(subStruct.triggerData);
@@ -585,8 +585,9 @@ function parseLiquityV2LeverageManagement(position: Position.Automated, parseDat
585
585
  _position.specific = {
586
586
  triggerRepayRatio: triggerData.ratio,
587
587
  targetRepayRatio: subData.targetRatio,
588
- repayEnabled: true,
588
+ repayEnabled: isEnabled,
589
589
  subId1: Number(subId),
590
+ subHashRepay: subHash,
590
591
  mergeWithId: Strategies.Identifiers.Boost,
591
592
  };
592
593
  } else {
@@ -595,6 +596,7 @@ function parseLiquityV2LeverageManagement(position: Position.Automated, parseDat
595
596
  targetBoostRatio: subData.targetRatio,
596
597
  boostEnabled: isEnabled,
597
598
  subId2: Number(subId),
599
+ subHashBoost: subHash,
598
600
  mergeId: Strategies.Identifiers.Boost,
599
601
  };
600
602
  }
@@ -847,6 +849,32 @@ function parseAaveV3OpenOrderFromCollateral(position: Position.Automated, parseD
847
849
  return _position;
848
850
  }
849
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.shouldClosePriceTrigger.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
+ // User can have:
868
+ // - Only TakeProfit
869
+ // - Only StopLoss
870
+ // - Both
871
+ // TODO: see on frontend what specific data we need here because stop-loss and take-profit is one bundle now
872
+ _position.strategy.strategyId = Strategies.Identifiers.CloseOnPrice;
873
+ _position.specific = {};
874
+
875
+ return _position;
876
+ }
877
+
850
878
  const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
851
879
  [ProtocolIdentifiers.StrategiesAutomation.MakerDAO]: {
852
880
  [Strategies.Identifiers.SavingsLiqProtection]: parseMakerSavingsLiqProtection,
@@ -870,6 +898,7 @@ const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
870
898
  [ProtocolIdentifiers.StrategiesAutomation.LiquityV2]: {
871
899
  [Strategies.Identifiers.Repay]: parseLiquityV2LeverageManagement,
872
900
  [Strategies.Identifiers.Boost]: parseLiquityV2LeverageManagement,
901
+ [Strategies.Identifiers.CloseOnPrice]: parseLiquityV2CloseOnPrice,
873
902
  },
874
903
  [ProtocolIdentifiers.StrategiesAutomation.AaveV2]: {
875
904
  [Strategies.Identifiers.Repay]: parseAaveV2LeverageManagement,
@@ -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(
@@ -537,6 +540,28 @@ export const liquityV2Encode = {
537
540
  // ? Bundles.MainnetIds.LIQUITY_V2_BOOST
538
541
  // : Bundles.MainnetIds.LIQUITY_V2_REPAY;
539
542
 
543
+ return [strategyOrBundleId, isBundle, triggerData, subData];
544
+ },
545
+ closeOnPrice(
546
+ strategyOrBundleId: number,
547
+ market: EthereumAddress,
548
+ troveId: string,
549
+ collToken: EthereumAddress,
550
+ boldToken: EthereumAddress,
551
+ stopLossPrice: number = 0,
552
+ stopLossType: CloseToAssetType = CloseToAssetType.DEBT,
553
+ takeProfitPrice: number = 0,
554
+ takeProfitType: CloseToAssetType = CloseToAssetType.COLLATERAL,
555
+ ) {
556
+ const isBundle = true;
557
+ const closeType = getCloseStrategyType(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType);
558
+
559
+ const subData = subDataService.liquityV2CloseSubData.encode(market, troveId, collToken, boldToken, closeType);
560
+ const triggerData = triggerService.shouldClosePriceTrigger.encode(collToken, stopLossPrice, takeProfitPrice);
561
+
562
+ // TODO: we can hardcode bundleID after testing
563
+ // Bundles.MainnetIds.LIQUITY_V2_CLOSE;
564
+
540
565
  return [strategyOrBundleId, isBundle, triggerData, subData];
541
566
  },
542
567
  };
@@ -6,7 +6,7 @@ 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';
9
+ import type { CloseStrategyType, OrderType } from '../types/enums';
10
10
  import {
11
11
  ChainId, CollActionType, DebtActionType, RatioState,
12
12
  } from '../types/enums';
@@ -679,3 +679,48 @@ export const liquityV2LeverageManagementSubData = {
679
679
  };
680
680
  },
681
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
+ };
@@ -470,3 +470,33 @@ export const liquityV2RatioTrigger = {
470
470
  };
471
471
  },
472
472
  };
473
+
474
+ export const shouldClosePriceTrigger = {
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
+ };
@@ -4,7 +4,9 @@ import AbiCoder from 'web3-eth-abi';
4
4
  import { getAssetInfo, getAssetInfoByAddress } from '@defisaver/tokens';
5
5
 
6
6
  import type { EthereumAddress } from '../types';
7
- import { ChainId, RatioState } from '../types/enums';
7
+ import {
8
+ ChainId, CloseStrategyType, CloseToAssetType, RatioState,
9
+ } from '../types/enums';
8
10
 
9
11
  export function isDefined<T>(value: T): value is NonNullable<T> {
10
12
  return value !== undefined && value !== null;
@@ -101,4 +103,36 @@ export function getRatioStateInfoForAaveCloseStrategy(
101
103
 
102
104
  export function getPositionId(...args: (number | string)[]) {
103
105
  return args.map(arg => arg.toString().toLowerCase().split(' ').join('_')).join('-');
106
+ }
107
+
108
+ export function getCloseStrategyType(
109
+ stopLossPrice: number,
110
+ stopLossType: CloseToAssetType,
111
+ takeProfitPrice: number,
112
+ takeProfitType: CloseToAssetType,
113
+ ): CloseStrategyType {
114
+ const isStopLoss = stopLossPrice > 0;
115
+ const isTakeProfit = takeProfitPrice > 0;
116
+
117
+ if (!isStopLoss && !isTakeProfit) {
118
+ throw new Error('CloseOnPrice: At least one price must be defined');
119
+ }
120
+
121
+ if (isStopLoss && isTakeProfit) {
122
+ if (stopLossType === CloseToAssetType.COLLATERAL && takeProfitType === CloseToAssetType.COLLATERAL) {
123
+ return CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL;
124
+ } if (stopLossType === CloseToAssetType.COLLATERAL) {
125
+ return CloseStrategyType.TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL;
126
+ } if (takeProfitType === CloseToAssetType.COLLATERAL) {
127
+ return CloseStrategyType.TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT;
128
+ }
129
+ return CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT;
130
+ } if (isStopLoss) {
131
+ return stopLossType === CloseToAssetType.COLLATERAL
132
+ ? CloseStrategyType.STOP_LOSS_IN_COLLATERAL
133
+ : CloseStrategyType.STOP_LOSS_IN_DEBT;
134
+ }
135
+ return takeProfitType === CloseToAssetType.COLLATERAL
136
+ ? CloseStrategyType.TAKE_PROFIT_IN_COLLATERAL
137
+ : CloseStrategyType.TAKE_PROFIT_IN_DEBT;
104
138
  }
@@ -31,6 +31,22 @@ export enum DebtActionType {
31
31
  BORROW = 1,
32
32
  }
33
33
 
34
+ export enum CloseStrategyType {
35
+ TAKE_PROFIT_IN_COLLATERAL = 0,
36
+ STOP_LOSS_IN_COLLATERAL = 1,
37
+ TAKE_PROFIT_IN_DEBT = 2,
38
+ STOP_LOSS_IN_DEBT = 3,
39
+ TAKE_PROFIT_AND_STOP_LOSS_IN_COLLATERAL = 4,
40
+ TAKE_PROFIT_IN_COLLATERAL_AND_STOP_LOSS_IN_DEBT = 5,
41
+ TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT = 6,
42
+ TAKE_PROFIT_IN_DEBT_AND_STOP_LOSS_IN_COLLATERAL = 7,
43
+ }
44
+
45
+ export enum CloseToAssetType {
46
+ COLLATERAL = 0,
47
+ DEBT = 1,
48
+ }
49
+
34
50
  /**
35
51
  * @dev Follow the naming convention:
36
52
  * - Enum name consists of two parts, name and version
@@ -112,6 +128,7 @@ export namespace Strategies {
112
128
  CloseToCollateralWithGasPrice = 'close-to-collateral-with-gas-price',
113
129
  CloseOnPriceToDebt = 'close-on-price-to-debt',
114
130
  CloseOnPriceToColl = 'close-on-price-to-collateral',
131
+ CloseOnPrice = 'close-on-price',
115
132
  TrailingStopToColl = 'trailing-stop-to-collateral',
116
133
  TrailingStopToDebt = 'trailing-stop-to-debt',
117
134
  Rebond = 'rebond',
@@ -177,6 +194,7 @@ export namespace Bundles {
177
194
  AAVE_V3_OPEN_ORDER_FROM_COLLATERAL = 36,
178
195
  LIQUITY_V2_REPAY = 37,
179
196
  LIQUITY_V2_BOOST = 38,
197
+ LIQUITY_V2_CLOSE = 39,
180
198
  }
181
199
 
182
200
  export enum OptimismIds {