@defisaver/automation-sdk 3.1.3 → 3.1.4-dev-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/automation/private/StrategiesAutomation.d.ts +2 -2
- package/cjs/automation/public/Strategies.test.d.ts +1 -0
- package/cjs/automation/public/Strategies.test.js +61 -0
- package/cjs/constants/index.js +35 -15
- package/cjs/services/strategiesService.js +68 -3
- package/cjs/services/strategySubService.d.ts +6 -2
- package/cjs/services/strategySubService.js +25 -3
- package/cjs/services/strategySubService.test.js +2 -2
- package/cjs/services/subDataService.d.ts +21 -2
- package/cjs/services/subDataService.js +56 -2
- package/cjs/services/subDataService.test.js +3 -3
- package/cjs/services/triggerService.d.ts +17 -0
- package/cjs/services/triggerService.js +33 -1
- package/cjs/services/utils.d.ts +6 -1
- package/cjs/services/utils.js +52 -1
- package/cjs/types/enums.d.ts +40 -11
- package/cjs/types/enums.js +37 -4
- package/cjs/types/index.d.ts +12 -3
- package/esm/automation/private/StrategiesAutomation.d.ts +2 -2
- package/esm/automation/public/Strategies.test.d.ts +1 -0
- package/esm/automation/public/Strategies.test.js +56 -0
- package/esm/constants/index.js +35 -15
- package/esm/services/strategiesService.js +69 -4
- package/esm/services/strategySubService.d.ts +6 -2
- package/esm/services/strategySubService.js +26 -4
- package/esm/services/strategySubService.test.js +2 -2
- package/esm/services/subDataService.d.ts +21 -2
- package/esm/services/subDataService.js +56 -2
- package/esm/services/subDataService.test.js +4 -4
- package/esm/services/triggerService.d.ts +17 -0
- package/esm/services/triggerService.js +32 -0
- package/esm/services/utils.d.ts +6 -1
- package/esm/services/utils.js +50 -1
- package/esm/types/enums.d.ts +40 -11
- package/esm/types/enums.js +36 -3
- package/esm/types/index.d.ts +12 -3
- package/package.json +1 -1
- package/src/automation/private/StrategiesAutomation.ts +2 -2
- package/src/automation/public/Strategies.test.ts +49 -0
- package/src/constants/index.ts +47 -16
- package/src/services/strategiesService.ts +89 -4
- package/src/services/strategySubService.test.ts +2 -2
- package/src/services/strategySubService.ts +52 -3
- package/src/services/subDataService.test.ts +4 -4
- package/src/services/subDataService.ts +85 -4
- package/src/services/triggerService.ts +53 -0
- package/src/services/utils.ts +60 -1
- package/src/types/enums.ts +36 -3
- 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
|
|
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
|
|
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
|
+
});
|
package/src/constants/index.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
ArbitrumBundleInfo,
|
|
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
|
|
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.
|
|
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]:
|
|
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('
|
|
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.
|
|
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 {
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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(
|
|
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 {
|
|
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
|
|
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
|
+
};
|