@defisaver/automation-sdk 3.3.7-dev.0 → 3.3.7-morpho-dev

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 (36) hide show
  1. package/cjs/constants/index.js +15 -0
  2. package/cjs/services/strategiesService.js +30 -0
  3. package/cjs/services/strategySubService.d.ts +1 -0
  4. package/cjs/services/strategySubService.js +7 -0
  5. package/cjs/services/strategySubService.test.js +38 -0
  6. package/cjs/services/subDataService.d.ts +12 -0
  7. package/cjs/services/subDataService.js +31 -1
  8. package/cjs/services/subDataService.test.js +52 -0
  9. package/cjs/services/triggerService.d.ts +10 -0
  10. package/cjs/services/triggerService.js +21 -1
  11. package/cjs/services/triggerService.test.js +48 -0
  12. package/cjs/types/enums.d.ts +6 -3
  13. package/cjs/types/enums.js +3 -0
  14. package/esm/constants/index.js +15 -0
  15. package/esm/services/strategiesService.js +30 -0
  16. package/esm/services/strategySubService.d.ts +1 -0
  17. package/esm/services/strategySubService.js +7 -0
  18. package/esm/services/strategySubService.test.js +38 -0
  19. package/esm/services/subDataService.d.ts +12 -0
  20. package/esm/services/subDataService.js +30 -0
  21. package/esm/services/subDataService.test.js +52 -0
  22. package/esm/services/triggerService.d.ts +10 -0
  23. package/esm/services/triggerService.js +20 -0
  24. package/esm/services/triggerService.test.js +49 -1
  25. package/esm/types/enums.d.ts +6 -3
  26. package/esm/types/enums.js +3 -0
  27. package/package.json +1 -1
  28. package/src/constants/index.ts +15 -0
  29. package/src/services/strategiesService.ts +43 -0
  30. package/src/services/strategySubService.test.ts +55 -0
  31. package/src/services/strategySubService.ts +21 -0
  32. package/src/services/subDataService.test.ts +59 -0
  33. package/src/services/subDataService.ts +40 -0
  34. package/src/services/triggerService.test.ts +53 -0
  35. package/src/services/triggerService.ts +32 -0
  36. package/src/types/enums.ts +3 -0
@@ -1264,6 +1264,58 @@ describe('Feature: subDataService.ts', () => {
1264
1264
  });
1265
1265
  });
1266
1266
  });
1267
+ describe('When testing subDataService.morphoBlueCloseOnPriceSubData', () => {
1268
+ describe('encode()', () => {
1269
+ const examples = [
1270
+ [
1271
+ [
1272
+ '0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
1273
+ '0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0',
1274
+ '0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc',
1275
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
1276
+ '0x0000000000000000000000000000000000000000000000000d1d507e40be8000',
1277
+ '0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c',
1278
+ '0x0000000000000000000000000000000000000000000000000000000000000006',
1279
+ ],
1280
+ [web3Utils.toChecksumAddress('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'), web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'), web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'), web3Utils.toChecksumAddress('0x0000000000000000000000000000000000000000'), '945000000000000000', web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'), CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT]
1281
+ ],
1282
+ ];
1283
+ examples.forEach(([expected, actual]) => {
1284
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
1285
+ expect(subDataService.morphoBlueCloseOnPriceSubData.encode(...actual)).to.eql(expected);
1286
+ });
1287
+ });
1288
+ });
1289
+ describe('decode()', () => {
1290
+ const examples = [
1291
+ [
1292
+ {
1293
+ loanToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
1294
+ collToken: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0',
1295
+ oracle: '0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC',
1296
+ irm: '0x0000000000000000000000000000000000000000',
1297
+ lltv: '945000000000000000',
1298
+ user: '0x1031d218133AFaB8C2B819B1366c7e434Ad91e9c',
1299
+ closeType: CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT,
1300
+ },
1301
+ [
1302
+ '0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
1303
+ '0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0',
1304
+ '0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc',
1305
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
1306
+ '0x0000000000000000000000000000000000000000000000000d1d507e40be8000',
1307
+ '0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c',
1308
+ '0x0000000000000000000000000000000000000000000000000000000000000006',
1309
+ ],
1310
+ ],
1311
+ ];
1312
+ examples.forEach(([expected, actual]) => {
1313
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1314
+ expect(subDataService.morphoBlueCloseOnPriceSubData.decode(actual)).to.eql(expected);
1315
+ });
1316
+ });
1317
+ });
1318
+ });
1267
1319
  describe('When testing subDataService.aaveV3LeverageManagementOnPriceSubData', () => {
1268
1320
  describe('encode()', () => {
1269
1321
  const examples = [
@@ -275,3 +275,13 @@ export declare const sparkQuotePriceRangeTrigger: {
275
275
  upperPrice: string;
276
276
  };
277
277
  };
278
+ export declare const morphoBluePriceRangeTrigger: {
279
+ encode(oracle: EthereumAddress, collateralToken: EthereumAddress, loanToken: EthereumAddress, lowerPrice: number, upperPrice: number): string[];
280
+ decode(triggerData: string[]): {
281
+ oracle: string;
282
+ collateralToken: string;
283
+ loanToken: string;
284
+ lowerPrice: string;
285
+ upperPrice: string;
286
+ };
287
+ };
@@ -498,3 +498,23 @@ export const sparkQuotePriceRangeTrigger = {
498
498
  };
499
499
  },
500
500
  };
501
+ export const morphoBluePriceRangeTrigger = {
502
+ encode(oracle, collateralToken, loanToken, lowerPrice, upperPrice) {
503
+ // Price is scaled to 1e8
504
+ const lowerPriceFormatted = new Dec(lowerPrice).mul(1e8).floor().toString();
505
+ const upperPriceFormatted = new Dec(upperPrice).mul(1e8).floor().toString();
506
+ return [
507
+ AbiCoder.encodeParameters(['address', 'address', 'address', 'uint256', 'uint256'], [oracle, collateralToken, loanToken, lowerPriceFormatted, upperPriceFormatted]),
508
+ ];
509
+ },
510
+ decode(triggerData) {
511
+ const decodedData = AbiCoder.decodeParameters(['address', 'address', 'address', 'uint256', 'uint256'], triggerData[0]);
512
+ return {
513
+ oracle: decodedData[0],
514
+ collateralToken: decodedData[1],
515
+ loanToken: decodedData[2],
516
+ lowerPrice: new Dec(decodedData[3]).div(1e8).toString(),
517
+ upperPrice: new Dec(decodedData[4]).div(1e8).toString(),
518
+ };
519
+ },
520
+ };
@@ -3,7 +3,7 @@ import { getAssetInfo, MAXUINT } from '@defisaver/tokens';
3
3
  import * as web3Utils from 'web3-utils';
4
4
  import { ChainId, OrderType, RatioState } from '../types/enums';
5
5
  import '../configuration';
6
- import { aaveV2RatioTrigger, aaveV3QuotePriceTrigger, aaveV3QuotePriceWithMaximumGasPriceTrigger, aaveV3RatioTrigger, cBondsRebondTrigger, chainlinkPriceTrigger, compoundV2RatioTrigger, compoundV3RatioTrigger, compoundV3PriceTrigger, curveUsdBorrowRateTrigger, curveUsdSoftLiquidationTrigger, exchangeOffchainPriceTrigger, exchangeTimestampTrigger, liquityDebtInFrontTrigger, makerRatioTrigger, morphoAaveV2RatioTrigger, sparkRatioTrigger, trailingStopTrigger, liquityDebtInFrontWithLimitTrigger, crvUSDRatioTrigger, morphoBlueRatioTrigger, crvUsdHealthRatioTrigger, liquityV2DebtInFrontTrigger, liquityV2AdjustTimeTrigger, compoundV3PriceRangeTrigger, aaveV3QuotePriceRangeTrigger, } from './triggerService';
6
+ import { aaveV2RatioTrigger, aaveV3QuotePriceTrigger, aaveV3QuotePriceWithMaximumGasPriceTrigger, aaveV3RatioTrigger, cBondsRebondTrigger, chainlinkPriceTrigger, compoundV2RatioTrigger, compoundV3RatioTrigger, compoundV3PriceTrigger, curveUsdBorrowRateTrigger, curveUsdSoftLiquidationTrigger, exchangeOffchainPriceTrigger, exchangeTimestampTrigger, liquityDebtInFrontTrigger, makerRatioTrigger, morphoAaveV2RatioTrigger, sparkRatioTrigger, trailingStopTrigger, liquityDebtInFrontWithLimitTrigger, crvUSDRatioTrigger, morphoBlueRatioTrigger, crvUsdHealthRatioTrigger, liquityV2DebtInFrontTrigger, liquityV2AdjustTimeTrigger, compoundV3PriceRangeTrigger, aaveV3QuotePriceRangeTrigger, morphoBluePriceRangeTrigger, } from './triggerService';
7
7
  describe('Feature: triggerService.ts', () => {
8
8
  describe('When testing triggerService.chainlinkPriceTrigger', () => {
9
9
  describe('encode()', () => {
@@ -1111,4 +1111,52 @@ describe('Feature: triggerService.ts', () => {
1111
1111
  });
1112
1112
  });
1113
1113
  });
1114
+ describe('When testing triggerService.morphoBluePriceRangeTrigger', () => {
1115
+ describe('encode()', () => {
1116
+ const examples = [
1117
+ [
1118
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000022ecb25c000000000000000000000000000000000000000000000000000000005d21dba000'],
1119
+ [web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'), web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'), web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), 1500, 4000]
1120
+ ],
1121
+ [
1122
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746a528800'],
1123
+ [web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'), web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'), web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), 0, 5000]
1124
+ ],
1125
+ ];
1126
+ examples.forEach(([expected, actual]) => {
1127
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
1128
+ expect(morphoBluePriceRangeTrigger.encode(...actual)).to.eql(expected);
1129
+ });
1130
+ });
1131
+ });
1132
+ describe('decode()', () => {
1133
+ const examples = [
1134
+ [
1135
+ {
1136
+ oracle: web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'),
1137
+ collateralToken: web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'),
1138
+ loanToken: web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
1139
+ lowerPrice: '1500',
1140
+ upperPrice: '4000',
1141
+ },
1142
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000022ecb25c000000000000000000000000000000000000000000000000000000005d21dba000'],
1143
+ ],
1144
+ [
1145
+ {
1146
+ oracle: web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'),
1147
+ collateralToken: web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'),
1148
+ loanToken: web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
1149
+ lowerPrice: '0',
1150
+ upperPrice: '5000',
1151
+ },
1152
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8dA6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746a528800'],
1153
+ ],
1154
+ ];
1155
+ examples.forEach(([expected, actual]) => {
1156
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1157
+ expect(morphoBluePriceRangeTrigger.decode(actual)).to.eql(expected);
1158
+ });
1159
+ });
1160
+ });
1161
+ });
1114
1162
  });
@@ -206,7 +206,8 @@ export declare namespace Bundles {
206
206
  AAVE_V3_EOA_REPAY_ON_PRICE = 54,
207
207
  AAVE_V3_EOA_BOOST_ON_PRICE = 55,
208
208
  AAVE_V3_EOA_CLOSE = 56,
209
- SPARK_CLOSE = 57
209
+ SPARK_CLOSE = 57,
210
+ MORPHO_BLUE_CLOSE = 58
210
211
  }
211
212
  enum OptimismIds {
212
213
  AAVE_V3_REPAY = 0,
@@ -247,7 +248,8 @@ export declare namespace Bundles {
247
248
  AAVE_V3_EOA_BOOST = 24,
248
249
  AAVE_V3_EOA_REPAY_ON_PRICE = 25,
249
250
  AAVE_V3_EOA_BOOST_ON_PRICE = 26,
250
- AAVE_V3_EOA_CLOSE = 27
251
+ AAVE_V3_EOA_CLOSE = 27,
252
+ MORPHO_BLUE_CLOSE = 28
251
253
  }
252
254
  enum ArbitrumIds {
253
255
  AAVE_V3_REPAY = 0,
@@ -277,6 +279,7 @@ export declare namespace Bundles {
277
279
  MORPHO_BLUE_BOOST = 24,
278
280
  MORPHO_BLUE_BOOST_ON_PRICE = 25,
279
281
  MORPHO_BLUE_EOA_REPAY = 26,
280
- MORPHO_BLUE_EOA_BOOST = 27
282
+ MORPHO_BLUE_EOA_BOOST = 27,
283
+ MORPHO_BLUE_CLOSE = 28
281
284
  }
282
285
  }
@@ -227,6 +227,7 @@ export var Bundles;
227
227
  MainnetIds[MainnetIds["AAVE_V3_EOA_BOOST_ON_PRICE"] = 55] = "AAVE_V3_EOA_BOOST_ON_PRICE";
228
228
  MainnetIds[MainnetIds["AAVE_V3_EOA_CLOSE"] = 56] = "AAVE_V3_EOA_CLOSE";
229
229
  MainnetIds[MainnetIds["SPARK_CLOSE"] = 57] = "SPARK_CLOSE";
230
+ MainnetIds[MainnetIds["MORPHO_BLUE_CLOSE"] = 58] = "MORPHO_BLUE_CLOSE";
230
231
  })(MainnetIds = Bundles.MainnetIds || (Bundles.MainnetIds = {}));
231
232
  let OptimismIds;
232
233
  (function (OptimismIds) {
@@ -270,6 +271,7 @@ export var Bundles;
270
271
  BaseIds[BaseIds["AAVE_V3_EOA_REPAY_ON_PRICE"] = 25] = "AAVE_V3_EOA_REPAY_ON_PRICE";
271
272
  BaseIds[BaseIds["AAVE_V3_EOA_BOOST_ON_PRICE"] = 26] = "AAVE_V3_EOA_BOOST_ON_PRICE";
272
273
  BaseIds[BaseIds["AAVE_V3_EOA_CLOSE"] = 27] = "AAVE_V3_EOA_CLOSE";
274
+ BaseIds[BaseIds["MORPHO_BLUE_CLOSE"] = 28] = "MORPHO_BLUE_CLOSE";
273
275
  })(BaseIds = Bundles.BaseIds || (Bundles.BaseIds = {}));
274
276
  let ArbitrumIds;
275
277
  (function (ArbitrumIds) {
@@ -301,5 +303,6 @@ export var Bundles;
301
303
  ArbitrumIds[ArbitrumIds["MORPHO_BLUE_BOOST_ON_PRICE"] = 25] = "MORPHO_BLUE_BOOST_ON_PRICE";
302
304
  ArbitrumIds[ArbitrumIds["MORPHO_BLUE_EOA_REPAY"] = 26] = "MORPHO_BLUE_EOA_REPAY";
303
305
  ArbitrumIds[ArbitrumIds["MORPHO_BLUE_EOA_BOOST"] = 27] = "MORPHO_BLUE_EOA_BOOST";
306
+ ArbitrumIds[ArbitrumIds["MORPHO_BLUE_CLOSE"] = 28] = "MORPHO_BLUE_CLOSE";
304
307
  })(ArbitrumIds = Bundles.ArbitrumIds || (Bundles.ArbitrumIds = {}));
305
308
  })(Bundles || (Bundles = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/automation-sdk",
3
- "version": "3.3.7-dev.0",
3
+ "version": "3.3.7-morpho-dev",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -491,6 +491,11 @@ export const MAINNET_BUNDLES_INFO: MainnetBundleInfo = {
491
491
  strategyId: Strategies.Identifiers.CloseOnPrice,
492
492
  protocol: PROTOCOLS.Spark,
493
493
  },
494
+ [Bundles.MainnetIds.MORPHO_BLUE_CLOSE]: {
495
+ strategyOrBundleId: Bundles.MainnetIds.MORPHO_BLUE_CLOSE,
496
+ strategyId: Strategies.Identifiers.CloseOnPrice,
497
+ protocol: PROTOCOLS.MorphoBlue,
498
+ },
494
499
  };
495
500
 
496
501
  export const OPTIMISM_BUNDLES_INFO: OptimismBundleInfo = {
@@ -683,6 +688,11 @@ export const BASE_BUNDLES_INFO: BaseBundleInfo = {
683
688
  strategyId: Strategies.Identifiers.EoaCloseOnPrice,
684
689
  protocol: PROTOCOLS.AaveV3,
685
690
  },
691
+ [Bundles.BaseIds.MORPHO_BLUE_CLOSE]: {
692
+ strategyOrBundleId: Bundles.BaseIds.MORPHO_BLUE_CLOSE,
693
+ strategyId: Strategies.Identifiers.CloseOnPrice,
694
+ protocol: PROTOCOLS.MorphoBlue,
695
+ },
686
696
  };
687
697
 
688
698
  export const ARBITRUM_BUNDLES_INFO: ArbitrumBundleInfo = {
@@ -826,6 +836,11 @@ export const ARBITRUM_BUNDLES_INFO: ArbitrumBundleInfo = {
826
836
  strategyId: Strategies.Identifiers.EoaBoost,
827
837
  protocol: PROTOCOLS.MorphoBlue,
828
838
  },
839
+ [Bundles.ArbitrumIds.MORPHO_BLUE_CLOSE]: {
840
+ strategyOrBundleId: Bundles.ArbitrumIds.MORPHO_BLUE_CLOSE,
841
+ strategyId: Strategies.Identifiers.CloseOnPrice,
842
+ protocol: PROTOCOLS.MorphoBlue,
843
+ },
829
844
  };
830
845
 
831
846
  export const BUNDLES_INFO: BundlesInfo = {
@@ -990,6 +990,48 @@ function parseMorphoBlueLeverageManagementOnPrice(position: Position.Automated,
990
990
  return _position;
991
991
  }
992
992
 
993
+ function parseMorphoBlueCloseOnPrice(position: Position.Automated, parseData: ParseData): Position.Automated {
994
+ const _position = cloneDeep(position);
995
+
996
+ const { subStruct } = parseData.subscriptionEventData;
997
+
998
+ const triggerData = triggerService.morphoBluePriceRangeTrigger.decode(subStruct.triggerData);
999
+ const subData = subDataService.morphoBlueCloseOnPriceSubData.decode(subStruct.subData);
1000
+
1001
+ _position.strategyData.decoded.triggerData = triggerData;
1002
+ _position.strategyData.decoded.subData = subData;
1003
+
1004
+ _position.positionId = getPositionId(_position.chainId, _position.protocol.id, _position.owner, Math.random());
1005
+
1006
+ const marketIdEncodedData = web3.eth.abi.encodeParameters(
1007
+ ['address', 'address', 'address', 'address', 'uint256'],
1008
+ [
1009
+ subData.loanToken,
1010
+ subData.collToken,
1011
+ subData.oracle,
1012
+ subData.irm,
1013
+ subData.lltv,
1014
+ ],
1015
+ );
1016
+
1017
+ const marketId = web3.utils.keccak256(marketIdEncodedData);
1018
+
1019
+ const { takeProfitType, stopLossType } = getStopLossAndTakeProfitTypeByCloseStrategyType(+subData.closeType);
1020
+
1021
+ _position.specific = {
1022
+ subHash: _position.subHash,
1023
+ marketId,
1024
+ collAsset: subData.collToken,
1025
+ debtAsset: subData.loanToken,
1026
+ stopLossPrice: triggerData.lowerPrice,
1027
+ takeProfitPrice: triggerData.upperPrice,
1028
+ stopLossType,
1029
+ takeProfitType,
1030
+ };
1031
+
1032
+ return _position;
1033
+ }
1034
+
993
1035
  function parseLiquityV2CloseOnPrice(position: Position.Automated, parseData: ParseData): Position.Automated {
994
1036
  const _position = cloneDeep(position);
995
1037
 
@@ -1208,6 +1250,7 @@ const parsingMethodsMapping: StrategiesToProtocolVersionMapping = {
1208
1250
  [Strategies.Identifiers.EoaRepay]: parseMorphoBlueLeverageManagement,
1209
1251
  [Strategies.Identifiers.EoaBoost]: parseMorphoBlueLeverageManagement,
1210
1252
  [Strategies.Identifiers.BoostOnPrice]: parseMorphoBlueLeverageManagementOnPrice,
1253
+ [Strategies.Identifiers.CloseOnPrice]: parseMorphoBlueCloseOnPrice,
1211
1254
  },
1212
1255
  [ProtocolIdentifiers.StrategiesAutomation.FluidT1]: {
1213
1256
  [Strategies.Identifiers.Repay]: parseFluidT1LeverageManagement,
@@ -1587,6 +1587,61 @@ describe('Feature: strategySubService.ts', () => {
1587
1587
  });
1588
1588
  });
1589
1589
  });
1590
+
1591
+ describe('closeOnPrice()', () => {
1592
+ const examples: Array<[
1593
+ [StrategyOrBundleIds, boolean, TriggerData, SubData],
1594
+ [
1595
+ strategyOrBundleId: number,
1596
+ loanToken: EthereumAddress,
1597
+ collToken: EthereumAddress,
1598
+ oracle: EthereumAddress,
1599
+ irm: EthereumAddress,
1600
+ lltv: string,
1601
+ user: EthereumAddress,
1602
+ stopLossPrice: number,
1603
+ stopLossType: CloseToAssetType,
1604
+ takeProfitPrice: number,
1605
+ takeProfitType: CloseToAssetType,
1606
+ ]
1607
+ ]> = [
1608
+ [
1609
+ [
1610
+ Bundles.MainnetIds.MORPHO_BLUE_CLOSE,
1611
+ true,
1612
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000022ecb25c000000000000000000000000000000000000000000000000000000005d21dba000'],
1613
+ [
1614
+ '0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
1615
+ '0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0',
1616
+ '0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc',
1617
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
1618
+ '0x0000000000000000000000000000000000000000000000000d1d507e40be8000',
1619
+ '0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c',
1620
+ '0x0000000000000000000000000000000000000000000000000000000000000005',
1621
+ ],
1622
+ ],
1623
+ [
1624
+ Bundles.MainnetIds.MORPHO_BLUE_CLOSE,
1625
+ web3Utils.toChecksumAddress('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'),
1626
+ web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'),
1627
+ web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'),
1628
+ web3Utils.toChecksumAddress('0x0000000000000000000000000000000000000000'),
1629
+ '945000000000000000',
1630
+ web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
1631
+ 1500,
1632
+ CloseToAssetType.DEBT,
1633
+ 4000,
1634
+ CloseToAssetType.COLLATERAL
1635
+ ]
1636
+ ],
1637
+ ];
1638
+
1639
+ examples.forEach(([expected, actual]) => {
1640
+ it(`Given ${JSON.stringify(actual)} should return expected value: ${JSON.stringify(expected)}`, () => {
1641
+ expect(morphoBlueEncode.closeOnPrice(...actual)).to.eql(expected);
1642
+ });
1643
+ });
1644
+ });
1590
1645
  });
1591
1646
 
1592
1647
  describe('When testing strategySubService.compoundV3L2Encode', () => {
@@ -670,6 +670,27 @@ export const morphoBlueEncode = {
670
670
  const triggerData = triggerService.morphoBluePriceTrigger.encode(oracle, collToken, loanToken, price, priceState);
671
671
  return [strategyOrBundleId, isBundle, triggerData, subData];
672
672
  },
673
+ closeOnPrice(
674
+ strategyOrBundleId: number,
675
+ loanToken: EthereumAddress,
676
+ collToken: EthereumAddress,
677
+ oracle: EthereumAddress,
678
+ irm: EthereumAddress,
679
+ lltv: string,
680
+ user: EthereumAddress,
681
+ stopLossPrice: number = 0,
682
+ stopLossType: CloseToAssetType = CloseToAssetType.DEBT,
683
+ takeProfitPrice: number = 0,
684
+ takeProfitType: CloseToAssetType = CloseToAssetType.COLLATERAL,
685
+ ) {
686
+ const isBundle = true;
687
+ const closeType = getCloseStrategyType(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType);
688
+
689
+ const subDataEncoded = subDataService.morphoBlueCloseOnPriceSubData.encode(loanToken, collToken, oracle, irm, lltv, user, closeType);
690
+ const triggerDataEncoded = triggerService.morphoBluePriceRangeTrigger.encode(oracle, collToken, loanToken, stopLossPrice, takeProfitPrice);
691
+
692
+ return [strategyOrBundleId, isBundle, triggerDataEncoded, subDataEncoded];
693
+ },
673
694
  };
674
695
 
675
696
  export const liquityV2Encode = {
@@ -1368,6 +1368,65 @@ describe('Feature: subDataService.ts', () => {
1368
1368
  });
1369
1369
  });
1370
1370
 
1371
+ describe('When testing subDataService.morphoBlueCloseOnPriceSubData', () => {
1372
+ describe('encode()', () => {
1373
+ const examples: Array<[
1374
+ SubData,
1375
+ [loanToken: EthereumAddress, collToken: EthereumAddress, oracle: EthereumAddress, irm: EthereumAddress, lltv: string, user: EthereumAddress, closeType: CloseStrategyType],
1376
+ ]> = [
1377
+ [
1378
+ [
1379
+ '0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
1380
+ '0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0',
1381
+ '0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc',
1382
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
1383
+ '0x0000000000000000000000000000000000000000000000000d1d507e40be8000',
1384
+ '0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c',
1385
+ '0x0000000000000000000000000000000000000000000000000000000000000006',
1386
+ ],
1387
+ [web3Utils.toChecksumAddress('0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'), web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'), web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'), web3Utils.toChecksumAddress('0x0000000000000000000000000000000000000000'), '945000000000000000', web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'), CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT]
1388
+ ],
1389
+ ];
1390
+
1391
+ examples.forEach(([expected, actual]) => {
1392
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
1393
+ expect(subDataService.morphoBlueCloseOnPriceSubData.encode(...actual)).to.eql(expected);
1394
+ });
1395
+ });
1396
+ });
1397
+
1398
+ describe('decode()', () => {
1399
+ const examples: Array<[{ loanToken: EthereumAddress, collToken: EthereumAddress, oracle: EthereumAddress, irm: EthereumAddress, lltv: string, user: EthereumAddress, closeType: CloseStrategyType }, SubData]> = [
1400
+ [
1401
+ {
1402
+ loanToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
1403
+ collToken: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0',
1404
+ oracle: '0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC',
1405
+ irm: '0x0000000000000000000000000000000000000000',
1406
+ lltv: '945000000000000000',
1407
+ user: '0x1031d218133AFaB8C2B819B1366c7e434Ad91e9c',
1408
+ closeType: CloseStrategyType.TAKE_PROFIT_AND_STOP_LOSS_IN_DEBT,
1409
+ },
1410
+ [
1411
+ '0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
1412
+ '0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0',
1413
+ '0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc',
1414
+ '0x0000000000000000000000000000000000000000000000000000000000000000',
1415
+ '0x0000000000000000000000000000000000000000000000000d1d507e40be8000',
1416
+ '0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c',
1417
+ '0x0000000000000000000000000000000000000000000000000000000000000006',
1418
+ ],
1419
+ ],
1420
+ ];
1421
+
1422
+ examples.forEach(([expected, actual]) => {
1423
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1424
+ expect(subDataService.morphoBlueCloseOnPriceSubData.decode(actual)).to.eql(expected);
1425
+ });
1426
+ });
1427
+ });
1428
+ });
1429
+
1371
1430
  describe('When testing subDataService.aaveV3LeverageManagementOnPriceSubData', () => {
1372
1431
  describe('encode()', () => {
1373
1432
  const examples: Array<[SubData, [collAsset: EthereumAddress, collAssetId: number, debtAsset: EthereumAddress, debtAssetId: number, marketAddr: EthereumAddress, targetRatio: number]]> = [
@@ -1212,3 +1212,43 @@ export const sparkCloseGenericSubData = {
1212
1212
  };
1213
1213
  },
1214
1214
  };
1215
+
1216
+ export const morphoBlueCloseOnPriceSubData = {
1217
+ encode(
1218
+ loanToken: EthereumAddress,
1219
+ collToken: EthereumAddress,
1220
+ oracle: EthereumAddress,
1221
+ irm: EthereumAddress,
1222
+ lltv: string,
1223
+ user: EthereumAddress,
1224
+ closeType: CloseStrategyType,
1225
+ ): SubData {
1226
+ const loanTokenEncoded = AbiCoder.encodeParameter('address', loanToken);
1227
+ const collTokenEncoded = AbiCoder.encodeParameter('address', collToken);
1228
+ const oracleEncoded = AbiCoder.encodeParameter('address', oracle);
1229
+ const irmEncoded = AbiCoder.encodeParameter('address', irm);
1230
+ const lltvEncoded = AbiCoder.encodeParameter('uint256', lltv);
1231
+ const userEncoded = AbiCoder.encodeParameter('address', user);
1232
+ const closeTypeEncoded = AbiCoder.encodeParameter('uint8', closeType);
1233
+ return [loanTokenEncoded, collTokenEncoded, oracleEncoded, irmEncoded, lltvEncoded, userEncoded, closeTypeEncoded];
1234
+ },
1235
+ decode(subData: SubData) {
1236
+ const loanToken = AbiCoder.decodeParameter('address', subData[0]) as unknown as EthereumAddress;
1237
+ const collToken = AbiCoder.decodeParameter('address', subData[1]) as any as EthereumAddress;
1238
+ const oracle = AbiCoder.decodeParameter('address', subData[2]) as any as EthereumAddress;
1239
+ const irm = AbiCoder.decodeParameter('address', subData[3]) as any as EthereumAddress;
1240
+ const lltv = AbiCoder.decodeParameter('uint256', subData[4]) as any as EthereumAddress;
1241
+ const user = AbiCoder.decodeParameter('address', subData[5]) as any as EthereumAddress;
1242
+ const closeType = Number(AbiCoder.decodeParameter('uint8', subData[6])) as CloseStrategyType;
1243
+
1244
+ return {
1245
+ loanToken,
1246
+ collToken,
1247
+ oracle,
1248
+ irm,
1249
+ lltv,
1250
+ user,
1251
+ closeType,
1252
+ };
1253
+ },
1254
+ };
@@ -31,6 +31,7 @@ import {
31
31
  crvUsdHealthRatioTrigger, liquityV2DebtInFrontTrigger, liquityV2AdjustTimeTrigger,
32
32
  compoundV3PriceRangeTrigger,
33
33
  aaveV3QuotePriceRangeTrigger,
34
+ morphoBluePriceRangeTrigger,
34
35
  } from './triggerService';
35
36
 
36
37
  describe('Feature: triggerService.ts', () => {
@@ -1230,4 +1231,56 @@ describe('Feature: triggerService.ts', () => {
1230
1231
  });
1231
1232
  });
1232
1233
  });
1234
+
1235
+ describe('When testing triggerService.morphoBluePriceRangeTrigger', () => {
1236
+ describe('encode()', () => {
1237
+ const examples: Array<[[string], [oracle: EthereumAddress, collateralToken: EthereumAddress, loanToken: EthereumAddress, lowerPrice: number, upperPrice: number]]> = [
1238
+ [
1239
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000022ecb25c000000000000000000000000000000000000000000000000000000005d21dba000'],
1240
+ [web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'), web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'), web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), 1500, 4000]
1241
+ ],
1242
+ [
1243
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746a528800'],
1244
+ [web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'), web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'), web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), 0, 5000]
1245
+ ],
1246
+ ];
1247
+
1248
+ examples.forEach(([expected, actual]) => {
1249
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
1250
+ expect(morphoBluePriceRangeTrigger.encode(...actual)).to.eql(expected);
1251
+ });
1252
+ });
1253
+ });
1254
+
1255
+ describe('decode()', () => {
1256
+ const examples: Array<[{ oracle: EthereumAddress, collateralToken: EthereumAddress, loanToken: EthereumAddress, lowerPrice: string, upperPrice: string }, TriggerData]> = [
1257
+ [
1258
+ {
1259
+ oracle: web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'),
1260
+ collateralToken: web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'),
1261
+ loanToken: web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
1262
+ lowerPrice: '1500',
1263
+ upperPrice: '4000',
1264
+ },
1265
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000022ecb25c000000000000000000000000000000000000000000000000000000005d21dba000'],
1266
+ ],
1267
+ [
1268
+ {
1269
+ oracle: web3Utils.toChecksumAddress('0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC'),
1270
+ collateralToken: web3Utils.toChecksumAddress('0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'),
1271
+ loanToken: web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
1272
+ lowerPrice: '0',
1273
+ upperPrice: '5000',
1274
+ },
1275
+ ['0x000000000000000000000000870ac11d48b15db9a138cf899d20f13f79ba00bc0000000000000000000000007f39c581f595b53c5cb19bd0b3f8dA6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746a528800'],
1276
+ ],
1277
+ ];
1278
+
1279
+ examples.forEach(([expected, actual]) => {
1280
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1281
+ expect(morphoBluePriceRangeTrigger.decode(actual)).to.eql(expected);
1282
+ });
1283
+ });
1284
+ });
1285
+ });
1233
1286
  });
@@ -688,4 +688,36 @@ export const sparkQuotePriceRangeTrigger = {
688
688
  upperPrice: new Dec(decodedData[3] as string).div(1e8).toString(),
689
689
  };
690
690
  },
691
+ };
692
+
693
+ export const morphoBluePriceRangeTrigger = {
694
+ encode(
695
+ oracle: EthereumAddress,
696
+ collateralToken: EthereumAddress,
697
+ loanToken: EthereumAddress,
698
+ lowerPrice: number,
699
+ upperPrice: number,
700
+ ) {
701
+ // Price is scaled to 1e8
702
+ const lowerPriceFormatted = new Dec(lowerPrice).mul(1e8).floor().toString();
703
+ const upperPriceFormatted = new Dec(upperPrice).mul(1e8).floor().toString();
704
+ return [
705
+ AbiCoder.encodeParameters(
706
+ ['address', 'address', 'address', 'uint256', 'uint256'],
707
+ [oracle, collateralToken, loanToken, lowerPriceFormatted, upperPriceFormatted],
708
+ ),
709
+ ];
710
+ },
711
+ decode(
712
+ triggerData: TriggerData,
713
+ ) {
714
+ const decodedData = AbiCoder.decodeParameters(['address', 'address', 'address', 'uint256', 'uint256'], triggerData[0]);
715
+ return {
716
+ oracle: decodedData[0] as EthereumAddress,
717
+ collateralToken: decodedData[1] as EthereumAddress,
718
+ loanToken: decodedData[2] as EthereumAddress,
719
+ lowerPrice: new Dec(decodedData[3] as string).div(1e8).toString(),
720
+ upperPrice: new Dec(decodedData[4] as string).div(1e8).toString(),
721
+ };
722
+ },
691
723
  };
@@ -222,6 +222,7 @@ export namespace Bundles {
222
222
  AAVE_V3_EOA_BOOST_ON_PRICE = 55,
223
223
  AAVE_V3_EOA_CLOSE = 56,
224
224
  SPARK_CLOSE = 57,
225
+ MORPHO_BLUE_CLOSE = 58,
225
226
  }
226
227
 
227
228
  export enum OptimismIds {
@@ -265,6 +266,7 @@ export namespace Bundles {
265
266
  AAVE_V3_EOA_REPAY_ON_PRICE = 25,
266
267
  AAVE_V3_EOA_BOOST_ON_PRICE = 26,
267
268
  AAVE_V3_EOA_CLOSE = 27,
269
+ MORPHO_BLUE_CLOSE = 28,
268
270
  }
269
271
 
270
272
  export enum ArbitrumIds {
@@ -296,6 +298,7 @@ export namespace Bundles {
296
298
  MORPHO_BLUE_BOOST_ON_PRICE = 25,
297
299
  MORPHO_BLUE_EOA_REPAY = 26,
298
300
  MORPHO_BLUE_EOA_BOOST = 27,
301
+ MORPHO_BLUE_CLOSE = 28,
299
302
  }
300
303
  }
301
304