@defisaver/automation-sdk 3.3.11 → 3.3.12

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 (54) hide show
  1. package/cjs/automation/private/StrategiesAutomation.d.ts +2 -0
  2. package/cjs/automation/private/StrategiesAutomation.js +10 -1
  3. package/cjs/automation/private/StrategiesAutomation.test.js +25 -0
  4. package/cjs/constants/index.d.ts +1 -0
  5. package/cjs/constants/index.js +62 -1
  6. package/cjs/services/strategiesService.js +104 -0
  7. package/cjs/services/strategySubService.d.ts +6 -0
  8. package/cjs/services/strategySubService.js +30 -1
  9. package/cjs/services/strategySubService.test.js +96 -0
  10. package/cjs/services/subDataService.d.ts +295 -137
  11. package/cjs/services/subDataService.js +639 -393
  12. package/cjs/services/subDataService.test.js +157 -0
  13. package/cjs/services/triggerService.d.ts +29 -0
  14. package/cjs/services/triggerService.js +53 -1
  15. package/cjs/services/triggerService.test.js +84 -0
  16. package/cjs/services/utils.d.ts +1 -1
  17. package/cjs/services/utils.js +10 -2
  18. package/cjs/types/enums.d.ts +17 -3
  19. package/cjs/types/enums.js +14 -0
  20. package/cjs/types/index.d.ts +22 -1
  21. package/esm/automation/private/StrategiesAutomation.d.ts +2 -0
  22. package/esm/automation/private/StrategiesAutomation.js +10 -1
  23. package/esm/automation/private/StrategiesAutomation.test.js +25 -0
  24. package/esm/constants/index.d.ts +1 -0
  25. package/esm/constants/index.js +61 -0
  26. package/esm/services/strategiesService.js +105 -1
  27. package/esm/services/strategySubService.d.ts +6 -0
  28. package/esm/services/strategySubService.js +29 -0
  29. package/esm/services/strategySubService.test.js +97 -1
  30. package/esm/services/subDataService.d.ts +295 -137
  31. package/esm/services/subDataService.js +639 -393
  32. package/esm/services/subDataService.test.js +157 -0
  33. package/esm/services/triggerService.d.ts +29 -0
  34. package/esm/services/triggerService.js +52 -0
  35. package/esm/services/triggerService.test.js +85 -1
  36. package/esm/services/utils.d.ts +1 -1
  37. package/esm/services/utils.js +10 -2
  38. package/esm/types/enums.d.ts +17 -3
  39. package/esm/types/enums.js +14 -0
  40. package/esm/types/index.d.ts +22 -1
  41. package/package.json +2 -2
  42. package/src/automation/private/StrategiesAutomation.test.ts +40 -0
  43. package/src/automation/private/StrategiesAutomation.ts +11 -0
  44. package/src/constants/index.ts +62 -0
  45. package/src/services/strategiesService.ts +119 -1
  46. package/src/services/strategySubService.test.ts +124 -0
  47. package/src/services/strategySubService.ts +118 -0
  48. package/src/services/subDataService.test.ts +172 -0
  49. package/src/services/subDataService.ts +1031 -782
  50. package/src/services/triggerService.test.ts +97 -0
  51. package/src/services/triggerService.ts +74 -1
  52. package/src/services/utils.ts +15 -4
  53. package/src/types/enums.ts +14 -0
  54. package/src/types/index.ts +26 -0
@@ -2118,4 +2118,161 @@ describe('Feature: subDataService.ts', () => {
2118
2118
  });
2119
2119
  });
2120
2120
  });
2121
+ describe('When testing subDataService.aaveV4LeverageManagementSubData', () => {
2122
+ describe('encode()', () => {
2123
+ const examples = [
2124
+ [
2125
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x00000000000000000000000000000000000000000000000014d1120d7b160000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2126
+ [web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'), RatioState.UNDER, 150]
2127
+ ],
2128
+ ];
2129
+ examples.forEach(([expected, actual]) => {
2130
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
2131
+ expect(subDataService.aaveV4LeverageManagementSubData.encode(...actual)).to.eql(expected);
2132
+ });
2133
+ });
2134
+ });
2135
+ describe('decode()', () => {
2136
+ const examples = [
2137
+ [
2138
+ {
2139
+ spoke: web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'),
2140
+ owner: web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
2141
+ ratioState: RatioState.UNDER,
2142
+ targetRatio: 150,
2143
+ },
2144
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x00000000000000000000000000000000000000000000000014d1120d7b160000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2145
+ ],
2146
+ ];
2147
+ examples.forEach(([expected, actual]) => {
2148
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
2149
+ expect(subDataService.aaveV4LeverageManagementSubData.decode(actual)).to.eql(expected);
2150
+ });
2151
+ });
2152
+ });
2153
+ });
2154
+ describe('When testing subDataService.aaveV4LeverageManagementOnPriceSubData', () => {
2155
+ describe('encode()', () => {
2156
+ const examples = [
2157
+ [
2158
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "0x0000000000000000000000000000000000000000000000000000000000000014", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x00000000000000000000000000000000000000000000000016345785d8a00000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2159
+ [
2160
+ web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
2161
+ web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), 10,
2162
+ web3Utils.toChecksumAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), 20,
2163
+ RatioState.OVER, 160
2164
+ ]
2165
+ ],
2166
+ ];
2167
+ examples.forEach(([expected, actual]) => {
2168
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
2169
+ expect(subDataService.aaveV4LeverageManagementOnPriceSubData.encode(...actual)).to.eql(expected);
2170
+ });
2171
+ });
2172
+ });
2173
+ describe('decode()', () => {
2174
+ const examples = [
2175
+ [
2176
+ {
2177
+ spoke: web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'),
2178
+ owner: web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
2179
+ collAsset: web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
2180
+ collAssetId: 10,
2181
+ debtAsset: web3Utils.toChecksumAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'),
2182
+ debtAssetId: 20,
2183
+ ratioState: RatioState.OVER,
2184
+ targetRatio: 160,
2185
+ },
2186
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "0x0000000000000000000000000000000000000000000000000000000000000014", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x00000000000000000000000000000000000000000000000016345785d8a00000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2187
+ ],
2188
+ ];
2189
+ examples.forEach(([expected, actual]) => {
2190
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
2191
+ expect(subDataService.aaveV4LeverageManagementOnPriceSubData.decode(actual)).to.eql(expected);
2192
+ });
2193
+ });
2194
+ });
2195
+ });
2196
+ describe('When testing subDataService.aaveV4CloseSubData', () => {
2197
+ describe('encode()', () => {
2198
+ const examples = [
2199
+ [
2200
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "0x0000000000000000000000000000000000000000000000000000000000000014", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2201
+ [
2202
+ web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
2203
+ web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), 10,
2204
+ web3Utils.toChecksumAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), 20,
2205
+ CloseStrategyType.STOP_LOSS_IN_COLLATERAL
2206
+ ]
2207
+ ],
2208
+ ];
2209
+ examples.forEach(([expected, actual]) => {
2210
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
2211
+ expect(subDataService.aaveV4CloseSubData.encode(...actual)).to.eql(expected);
2212
+ });
2213
+ });
2214
+ });
2215
+ describe('decode()', () => {
2216
+ const examples = [
2217
+ [
2218
+ {
2219
+ spoke: web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'),
2220
+ owner: web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
2221
+ collAsset: web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
2222
+ collAssetId: 10,
2223
+ debtAsset: web3Utils.toChecksumAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'),
2224
+ debtAssetId: 20,
2225
+ closeType: CloseStrategyType.STOP_LOSS_IN_COLLATERAL,
2226
+ },
2227
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "0x0000000000000000000000000000000000000000000000000000000000000014", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2228
+ ],
2229
+ ];
2230
+ examples.forEach(([expected, actual]) => {
2231
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
2232
+ expect(subDataService.aaveV4CloseSubData.decode(actual)).to.eql(expected);
2233
+ });
2234
+ });
2235
+ });
2236
+ });
2237
+ describe('When testing subDataService.aaveV4CollateralSwitchSubData', () => {
2238
+ describe('encode()', () => {
2239
+ const examples = [
2240
+ [
2241
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "0x0000000000000000000000000000000000000000000000000000000000000014", "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2242
+ [
2243
+ web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
2244
+ web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), 10,
2245
+ web3Utils.toChecksumAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), 20,
2246
+ '1000000000000000000'
2247
+ ]
2248
+ ],
2249
+ ];
2250
+ examples.forEach(([expected, actual]) => {
2251
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
2252
+ expect(subDataService.aaveV4CollateralSwitchSubData.encode(...actual)).to.eql(expected);
2253
+ });
2254
+ });
2255
+ });
2256
+ describe('decode()', () => {
2257
+ const examples = [
2258
+ [
2259
+ {
2260
+ spoke: web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'),
2261
+ owner: web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'),
2262
+ fromAsset: web3Utils.toChecksumAddress('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'),
2263
+ fromAssetId: 10,
2264
+ toAsset: web3Utils.toChecksumAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'),
2265
+ toAssetId: 20,
2266
+ amountToSwitch: '1000000000000000000'
2267
+ },
2268
+ ["0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e", "0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c", "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0x000000000000000000000000000000000000000000000000000000000000000a", "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "0x0000000000000000000000000000000000000000000000000000000000000014", "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"],
2269
+ ],
2270
+ ];
2271
+ examples.forEach(([expected, actual]) => {
2272
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
2273
+ expect(subDataService.aaveV4CollateralSwitchSubData.decode(actual)).to.eql(expected);
2274
+ });
2275
+ });
2276
+ });
2277
+ });
2121
2278
  });
@@ -294,3 +294,32 @@ export declare const sparkQuotePriceTrigger: {
294
294
  ratioState: number;
295
295
  };
296
296
  };
297
+ export declare const aaveV4RatioTrigger: {
298
+ encode(owner: EthereumAddress, spoke: EthereumAddress, ratioPercentage: number, ratioState: RatioState): string[];
299
+ decode(triggerData: string[]): {
300
+ owner: string;
301
+ spoke: string;
302
+ ratio: number;
303
+ ratioState: number;
304
+ };
305
+ };
306
+ export declare const aaveV4QuotePriceTrigger: {
307
+ encode(spoke: EthereumAddress, baseTokenId: number, quoteTokenId: number, price: string, ratioState: RatioState): string[];
308
+ decode(triggerData: string[]): {
309
+ spoke: string;
310
+ baseTokenId: number;
311
+ quoteTokenId: number;
312
+ price: string;
313
+ ratioState: number;
314
+ };
315
+ };
316
+ export declare const aaveV4QuotePriceRangeTrigger: {
317
+ encode(spoke: EthereumAddress, baseTokenId: number, quoteTokenId: number, lowerPrice: string, upperPrice: string): string[];
318
+ decode(triggerData: string[]): {
319
+ spoke: string;
320
+ baseTokenId: number;
321
+ quoteTokenId: number;
322
+ lowerPrice: string;
323
+ upperPrice: string;
324
+ };
325
+ };
@@ -533,3 +533,55 @@ export const sparkQuotePriceTrigger = {
533
533
  };
534
534
  },
535
535
  };
536
+ export const aaveV4RatioTrigger = {
537
+ encode(owner, spoke, ratioPercentage, ratioState) {
538
+ const ratioWei = ratioPercentageToWei(ratioPercentage);
539
+ return [AbiCoder.encodeParameters(['address', 'address', 'uint256', 'uint8'], [owner, spoke, ratioWei, ratioState])];
540
+ },
541
+ decode(triggerData) {
542
+ const decodedData = AbiCoder.decodeParameters(['address', 'address', 'uint256', 'uint8'], triggerData[0]);
543
+ return {
544
+ owner: decodedData[0],
545
+ spoke: decodedData[1],
546
+ ratio: weiToRatioPercentage(decodedData[2]),
547
+ ratioState: Number(decodedData[3]),
548
+ };
549
+ },
550
+ };
551
+ export const aaveV4QuotePriceTrigger = {
552
+ encode(spoke, baseTokenId, quoteTokenId, price, ratioState) {
553
+ // Price is intentionally scaled to 1e18 for higher precision.
554
+ const _price = new Dec(price).mul(1e18).floor().toString();
555
+ return [AbiCoder.encodeParameters(['address', 'uint256', 'uint256', 'uint256', 'uint8'], [spoke, baseTokenId, quoteTokenId, _price, ratioState])];
556
+ },
557
+ decode(triggerData) {
558
+ const decodedData = AbiCoder.decodeParameters(['address', 'uint256', 'uint256', 'uint256', 'uint8'], triggerData[0]);
559
+ return {
560
+ spoke: decodedData[0],
561
+ baseTokenId: Number(decodedData[1]),
562
+ quoteTokenId: Number(decodedData[2]),
563
+ price: new Dec(decodedData[3]).div(1e18).toString(),
564
+ ratioState: Number(decodedData[4]),
565
+ };
566
+ },
567
+ };
568
+ export const aaveV4QuotePriceRangeTrigger = {
569
+ encode(spoke, baseTokenId, quoteTokenId, lowerPrice, upperPrice) {
570
+ // Price is intentionally scaled to 1e18 for higher precision.
571
+ const lowerPriceFormatted = new Dec(lowerPrice).mul(1e18).floor().toString();
572
+ const upperPriceFormatted = new Dec(upperPrice).mul(1e18).floor().toString();
573
+ return [
574
+ AbiCoder.encodeParameters(['address', 'uint256', 'uint256', 'uint256', 'uint256'], [spoke, baseTokenId, quoteTokenId, lowerPriceFormatted, upperPriceFormatted]),
575
+ ];
576
+ },
577
+ decode(triggerData) {
578
+ const decodedData = AbiCoder.decodeParameters(['address', 'uint256', 'uint256', 'uint256', 'uint256'], triggerData[0]);
579
+ return {
580
+ spoke: decodedData[0],
581
+ baseTokenId: Number(decodedData[1]),
582
+ quoteTokenId: Number(decodedData[2]),
583
+ lowerPrice: new Dec(decodedData[3]).div(1e18).toString(),
584
+ upperPrice: new Dec(decodedData[4]).div(1e18).toString(),
585
+ };
586
+ },
587
+ };
@@ -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, morphoBluePriceRangeTrigger, sparkQuotePriceTrigger, } 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, sparkQuotePriceTrigger, aaveV4RatioTrigger, aaveV4QuotePriceTrigger, aaveV4QuotePriceRangeTrigger, } from './triggerService';
7
7
  describe('Feature: triggerService.ts', () => {
8
8
  describe('When testing triggerService.chainlinkPriceTrigger', () => {
9
9
  describe('encode()', () => {
@@ -1159,6 +1159,90 @@ describe('Feature: triggerService.ts', () => {
1159
1159
  });
1160
1160
  });
1161
1161
  });
1162
+ describe('When testing triggerService.aaveV4RatioTrigger', () => {
1163
+ describe('encode()', () => {
1164
+ const examples = [
1165
+ [
1166
+ ['0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e00000000000000000000000000000000000000000000000010a741a4627800000000000000000000000000000000000000000000000000000000000000000001'],
1167
+ [web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'), web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), 120, RatioState.UNDER]
1168
+ ],
1169
+ ];
1170
+ examples.forEach(([expected, actual]) => {
1171
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
1172
+ expect(aaveV4RatioTrigger.encode(...actual)).to.eql(expected);
1173
+ });
1174
+ });
1175
+ });
1176
+ describe('decode()', () => {
1177
+ const examples = [
1178
+ [
1179
+ { owner: web3Utils.toChecksumAddress('0x1031d218133AFaB8c2B819B1366c7E434Ad91E9c'), spoke: web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), ratio: 120, ratioState: RatioState.UNDER },
1180
+ ['0x0000000000000000000000001031d218133afab8c2b819b1366c7e434ad91e9c0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e00000000000000000000000000000000000000000000000010a741a4627800000000000000000000000000000000000000000000000000000000000000000001'],
1181
+ ],
1182
+ ];
1183
+ examples.forEach(([expected, actual]) => {
1184
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1185
+ expect(aaveV4RatioTrigger.decode(actual)).to.eql(expected);
1186
+ });
1187
+ });
1188
+ });
1189
+ });
1190
+ describe('When testing triggerService.aaveV4QuotePriceTrigger', () => {
1191
+ describe('encode()', () => {
1192
+ const examples = [
1193
+ [
1194
+ ['0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000000000000'],
1195
+ [web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), 10, 20, '1500', RatioState.OVER]
1196
+ ],
1197
+ ];
1198
+ examples.forEach(([expected, actual]) => {
1199
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
1200
+ expect(aaveV4QuotePriceTrigger.encode(...actual)).to.eql(expected);
1201
+ });
1202
+ });
1203
+ });
1204
+ describe('decode()', () => {
1205
+ const examples = [
1206
+ [
1207
+ { spoke: web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), baseTokenId: 10, quoteTokenId: 20, price: '1500', ratioState: RatioState.OVER },
1208
+ ['0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000000000000000000000000000000000000000000000'],
1209
+ ],
1210
+ ];
1211
+ examples.forEach(([expected, actual]) => {
1212
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1213
+ expect(aaveV4QuotePriceTrigger.decode(actual)).to.eql(expected);
1214
+ });
1215
+ });
1216
+ });
1217
+ });
1218
+ describe('When testing triggerService.aaveV4QuotePriceRangeTrigger', () => {
1219
+ describe('encode()', () => {
1220
+ const examples = [
1221
+ [
1222
+ ['0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000004be4e7267b6ae00000000000000000000000000000000000000000000000000056bc75e2d631000000'],
1223
+ [web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), 10, 20, '1400', '1600']
1224
+ ],
1225
+ ];
1226
+ examples.forEach(([expected, actual]) => {
1227
+ it(`Given ${actual} should return expected value: ${expected}`, () => {
1228
+ expect(aaveV4QuotePriceRangeTrigger.encode(...actual)).to.eql(expected);
1229
+ });
1230
+ });
1231
+ });
1232
+ describe('decode()', () => {
1233
+ const examples = [
1234
+ [
1235
+ { spoke: web3Utils.toChecksumAddress('0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e'), baseTokenId: 10, quoteTokenId: 20, lowerPrice: '1400', upperPrice: '1600' },
1236
+ ['0x0000000000000000000000002f39d218133afab8f2b819b1066c7e434ad94e9e000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000004be4e7267b6ae00000000000000000000000000000000000000000000000000056bc75e2d631000000'],
1237
+ ],
1238
+ ];
1239
+ examples.forEach(([expected, actual]) => {
1240
+ it(`Given ${actual} should return expected value: ${JSON.stringify(expected)}`, () => {
1241
+ expect(aaveV4QuotePriceRangeTrigger.decode(actual)).to.eql(expected);
1242
+ });
1243
+ });
1244
+ });
1245
+ });
1162
1246
  describe('When testing triggerService.sparkQuotePriceTrigger', () => {
1163
1247
  describe('encode()', () => {
1164
1248
  const examples = [
@@ -23,7 +23,7 @@ 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
+ export declare function getCloseStrategyType(stopLossPrice: number | string, stopLossType: CloseToAssetType, takeProfitPrice: number | string, takeProfitType: CloseToAssetType): CloseStrategyType;
27
27
  export declare function getStopLossAndTakeProfitTypeByCloseStrategyType(closeStrategyType: CloseStrategyType): {
28
28
  stopLossType: CloseToAssetType | undefined;
29
29
  takeProfitType: CloseToAssetType | undefined;
@@ -81,8 +81,16 @@ export function getPositionId(...args) {
81
81
  return args.map(arg => arg.toString().toLowerCase().split(' ').join('_')).join('-');
82
82
  }
83
83
  export function getCloseStrategyType(stopLossPrice, stopLossType, takeProfitPrice, takeProfitType) {
84
- const isStopLoss = stopLossPrice > 0;
85
- const isTakeProfit = takeProfitPrice > 0;
84
+ const stopLossPriceDec = new Dec(stopLossPrice);
85
+ const takeProfitPriceDec = new Dec(takeProfitPrice);
86
+ if (!stopLossPriceDec.isFinite() || stopLossPriceDec.isNegative()) {
87
+ throw new Error('CloseOnPrice: stopLossPrice must be a finite non-negative number');
88
+ }
89
+ if (!takeProfitPriceDec.isFinite() || takeProfitPriceDec.isNegative()) {
90
+ throw new Error('CloseOnPrice: takeProfitPrice must be a finite non-negative number');
91
+ }
92
+ const isStopLoss = stopLossPriceDec.gt(0);
93
+ const isTakeProfit = takeProfitPriceDec.gt(0);
86
94
  if (!isStopLoss && !isTakeProfit) {
87
95
  throw new Error('CloseOnPrice: At least one price must be defined');
88
96
  }
@@ -56,6 +56,7 @@ export declare namespace ProtocolIdentifiers {
56
56
  CompoundV3 = "Compound__V3",
57
57
  AaveV2 = "Aave__V2",
58
58
  AaveV3 = "Aave__V3",
59
+ AaveV4 = "Aave__V4",
59
60
  MorphoAaveV2 = "Morpho-Aave__V2",
60
61
  Exchange = "Exchange",
61
62
  Spark = "Spark",
@@ -86,7 +87,9 @@ export declare namespace Strategies {
86
87
  LIQUITY_DEBT_IN_FRONT_REPAY = 75,
87
88
  CURVEUSD_PAYBACK = 92,
88
89
  LIQUITY_V2_PAYBACK = 113,
89
- AAVE_V3_COLLATERAL_SWITCH = 135
90
+ AAVE_V3_COLLATERAL_SWITCH = 135,
91
+ AAVE_V4_COLLATERAL_SWITCH = 154,
92
+ AAVE_V4_COLLATERAL_SWITCH_EOA = 155
90
93
  }
91
94
  enum OptimismIds {
92
95
  EXCHANGE_DCA = 8,
@@ -133,7 +136,8 @@ export declare namespace Strategies {
133
136
  RepayOnPrice = "repay-on-price",
134
137
  EoaBoostOnPrice = "eoa-boost-on-price",
135
138
  EoaRepayOnPrice = "eoa-repay-on-price",
136
- CollateralSwitch = "collateral-switch"
139
+ CollateralSwitch = "collateral-switch",
140
+ EoaCollateralSwitch = "eoa-collateral-switch"
137
141
  }
138
142
  enum IdOverrides {
139
143
  TakeProfit = "take-profit",
@@ -209,7 +213,17 @@ export declare namespace Bundles {
209
213
  SPARK_CLOSE = 57,
210
214
  MORPHO_BLUE_CLOSE = 58,
211
215
  SPARK_REPAY_ON_PRICE = 59,
212
- SPARK_BOOST_ON_PRICE = 60
216
+ SPARK_BOOST_ON_PRICE = 60,
217
+ AAVE_V4_REPAY = 61,
218
+ AAVE_V4_BOOST = 62,
219
+ AAVE_V4_REPAY_ON_PRICE = 63,
220
+ AAVE_V4_BOOST_ON_PRICE = 64,
221
+ AAVE_V4_CLOSE = 65,
222
+ AAVE_V4_EOA_REPAY = 66,
223
+ AAVE_V4_EOA_BOOST = 67,
224
+ AAVE_V4_EOA_REPAY_ON_PRICE = 68,
225
+ AAVE_V4_EOA_BOOST_ON_PRICE = 69,
226
+ AAVE_V4_EOA_CLOSE = 70
213
227
  }
214
228
  enum OptimismIds {
215
229
  AAVE_V3_REPAY = 0,
@@ -66,6 +66,7 @@ export var ProtocolIdentifiers;
66
66
  StrategiesAutomation["CompoundV3"] = "Compound__V3";
67
67
  StrategiesAutomation["AaveV2"] = "Aave__V2";
68
68
  StrategiesAutomation["AaveV3"] = "Aave__V3";
69
+ StrategiesAutomation["AaveV4"] = "Aave__V4";
69
70
  StrategiesAutomation["MorphoAaveV2"] = "Morpho-Aave__V2";
70
71
  StrategiesAutomation["Exchange"] = "Exchange";
71
72
  StrategiesAutomation["Spark"] = "Spark";
@@ -100,6 +101,8 @@ export var Strategies;
100
101
  MainnetIds[MainnetIds["CURVEUSD_PAYBACK"] = 92] = "CURVEUSD_PAYBACK";
101
102
  MainnetIds[MainnetIds["LIQUITY_V2_PAYBACK"] = 113] = "LIQUITY_V2_PAYBACK";
102
103
  MainnetIds[MainnetIds["AAVE_V3_COLLATERAL_SWITCH"] = 135] = "AAVE_V3_COLLATERAL_SWITCH";
104
+ MainnetIds[MainnetIds["AAVE_V4_COLLATERAL_SWITCH"] = 154] = "AAVE_V4_COLLATERAL_SWITCH";
105
+ MainnetIds[MainnetIds["AAVE_V4_COLLATERAL_SWITCH_EOA"] = 155] = "AAVE_V4_COLLATERAL_SWITCH_EOA";
103
106
  })(MainnetIds = Strategies.MainnetIds || (Strategies.MainnetIds = {}));
104
107
  let OptimismIds;
105
108
  (function (OptimismIds) {
@@ -151,6 +154,7 @@ export var Strategies;
151
154
  Identifiers["EoaBoostOnPrice"] = "eoa-boost-on-price";
152
155
  Identifiers["EoaRepayOnPrice"] = "eoa-repay-on-price";
153
156
  Identifiers["CollateralSwitch"] = "collateral-switch";
157
+ Identifiers["EoaCollateralSwitch"] = "eoa-collateral-switch";
154
158
  })(Identifiers = Strategies.Identifiers || (Strategies.Identifiers = {}));
155
159
  let IdOverrides;
156
160
  (function (IdOverrides) {
@@ -230,6 +234,16 @@ export var Bundles;
230
234
  MainnetIds[MainnetIds["MORPHO_BLUE_CLOSE"] = 58] = "MORPHO_BLUE_CLOSE";
231
235
  MainnetIds[MainnetIds["SPARK_REPAY_ON_PRICE"] = 59] = "SPARK_REPAY_ON_PRICE";
232
236
  MainnetIds[MainnetIds["SPARK_BOOST_ON_PRICE"] = 60] = "SPARK_BOOST_ON_PRICE";
237
+ MainnetIds[MainnetIds["AAVE_V4_REPAY"] = 61] = "AAVE_V4_REPAY";
238
+ MainnetIds[MainnetIds["AAVE_V4_BOOST"] = 62] = "AAVE_V4_BOOST";
239
+ MainnetIds[MainnetIds["AAVE_V4_REPAY_ON_PRICE"] = 63] = "AAVE_V4_REPAY_ON_PRICE";
240
+ MainnetIds[MainnetIds["AAVE_V4_BOOST_ON_PRICE"] = 64] = "AAVE_V4_BOOST_ON_PRICE";
241
+ MainnetIds[MainnetIds["AAVE_V4_CLOSE"] = 65] = "AAVE_V4_CLOSE";
242
+ MainnetIds[MainnetIds["AAVE_V4_EOA_REPAY"] = 66] = "AAVE_V4_EOA_REPAY";
243
+ MainnetIds[MainnetIds["AAVE_V4_EOA_BOOST"] = 67] = "AAVE_V4_EOA_BOOST";
244
+ MainnetIds[MainnetIds["AAVE_V4_EOA_REPAY_ON_PRICE"] = 68] = "AAVE_V4_EOA_REPAY_ON_PRICE";
245
+ MainnetIds[MainnetIds["AAVE_V4_EOA_BOOST_ON_PRICE"] = 69] = "AAVE_V4_EOA_BOOST_ON_PRICE";
246
+ MainnetIds[MainnetIds["AAVE_V4_EOA_CLOSE"] = 70] = "AAVE_V4_EOA_CLOSE";
233
247
  })(MainnetIds = Bundles.MainnetIds || (Bundles.MainnetIds = {}));
234
248
  let OptimismIds;
235
249
  (function (OptimismIds) {
@@ -208,8 +208,29 @@ export declare namespace Position {
208
208
  ratioState: RatioState;
209
209
  ratio: number;
210
210
  }
211
+ interface CloseBase extends Base {
212
+ stopLossPrice: string;
213
+ takeProfitPrice: string;
214
+ stopLossType: CloseToAssetType | undefined;
215
+ takeProfitType: CloseToAssetType | undefined;
216
+ }
217
+ interface AaveV4LeverageManagementOnPrice extends Base {
218
+ collAsset: EthereumAddress;
219
+ collAssetId: number;
220
+ debtAsset: EthereumAddress;
221
+ debtAssetId: number;
222
+ price: string;
223
+ ratioState: number;
224
+ ratio: number;
225
+ }
226
+ interface AaveV4CloseOnPrice extends CloseBase {
227
+ collAsset: EthereumAddress;
228
+ collAssetId: number;
229
+ debtAsset: EthereumAddress;
230
+ debtAssetId: number;
231
+ }
211
232
  }
212
- type SpecificAny = Specific.CloseOnPrice | Specific.TrailingStop | Specific.RatioProtection | Specific.CloseOnPriceAave | Specific.BoostOnPriceAave | Specific.CloseOnPriceWithMaximumGasPriceAave | Specific.DebtInFrontRepay | Specific.LeverageManagementCrvUSD | Specific.CloseOnPriceLiquityV2 | Specific.BoostOnPriceMorpho | Specific.BoostOnPriceLiquityV2 | Specific.PaybackLiquityV2 | Specific.CompoundV3LeverageManagementOnPrice | Specific.CompoundV3CloseOnPrice | Specific.AaveV3CloseOnPriceGeneric | Specific.SparkOnPrice;
233
+ type SpecificAny = Specific.CloseOnPrice | Specific.TrailingStop | Specific.RatioProtection | Specific.CloseOnPriceAave | Specific.BoostOnPriceAave | Specific.CloseOnPriceWithMaximumGasPriceAave | Specific.DebtInFrontRepay | Specific.LeverageManagementCrvUSD | Specific.CloseOnPriceLiquityV2 | Specific.BoostOnPriceMorpho | Specific.BoostOnPriceLiquityV2 | Specific.PaybackLiquityV2 | Specific.CompoundV3LeverageManagementOnPrice | Specific.CompoundV3CloseOnPrice | Specific.AaveV3CloseOnPriceGeneric | Specific.AaveV4LeverageManagementOnPrice | Specific.AaveV4CloseOnPrice | Specific.SparkOnPrice;
213
234
  interface Automated {
214
235
  chainId: ChainId;
215
236
  positionId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defisaver/automation-sdk",
3
- "version": "3.3.11",
3
+ "version": "3.3.12",
4
4
  "description": "",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./esm/index.js",
@@ -23,7 +23,7 @@
23
23
  "repository": "https://github.com/defisaver/automation-sdk",
24
24
  "license": "ISC",
25
25
  "dependencies": {
26
- "@defisaver/sdk": "^1.3.21",
26
+ "@defisaver/sdk": "^1.3.22",
27
27
  "@defisaver/tokens": "^1.6.19",
28
28
  "@ethersproject/address": "^5.0.10",
29
29
  "@ethersproject/solidity": "^5.0.9",
@@ -659,5 +659,45 @@ describe('Feature: StrategiesAutomation.ts', () => {
659
659
  expect(JSON.stringify(actual)).to.equal(JSON.stringify(expected));
660
660
  });
661
661
  });
662
+
663
+ it('Aave V4: pairs repay/boost merge only when trigger spoke matches (no cross-spoke merge)', () => {
664
+ const spoke1 = '0x0000000000000000000000000000000000000a01';
665
+ const spoke2 = '0x0000000000000000000000000000000000000a02';
666
+ const base = {
667
+ isEnabled: true,
668
+ chainId: 1,
669
+ owner: '0x0000000000000000000000000000000000000b01',
670
+ protocol: { id: 'Aave__V4' },
671
+ strategy: { strategyId: 'leverage-management' },
672
+ blockNumber: 0,
673
+ subHash: '0x1',
674
+ positionId: 'test',
675
+ };
676
+ const boostSpoke1 = {
677
+ ...base,
678
+ subId: 1,
679
+ strategyData: { decoded: { triggerData: { spoke: spoke1 }, subData: {} } },
680
+ specific: { mergeId: 'boost', subId2: 1 },
681
+ };
682
+ const repaySpoke2 = {
683
+ ...base,
684
+ subId: 2,
685
+ strategyData: { decoded: { triggerData: { spoke: spoke2 }, subData: {} } },
686
+ specific: { mergeWithId: 'boost', subId1: 2 },
687
+ };
688
+ const boostSpoke2 = {
689
+ ...base,
690
+ subId: 3,
691
+ strategyData: { decoded: { triggerData: { spoke: spoke2 }, subData: {} } },
692
+ specific: { mergeId: 'boost', subId2: 3 },
693
+ };
694
+ // @ts-ignore — mergeSubs is protected; exercised here as in examples above
695
+ const merged = exampleStrategiesAutomation.mergeSubs([boostSpoke1, repaySpoke2, boostSpoke2]);
696
+ expect(merged).to.have.length(2);
697
+ const mergedPair = merged.find((m: { subIds?: number[] }) => m.subIds?.length === 2);
698
+ const loneBoost = merged.find((m: { subIds?: number[] }) => m.subIds?.length === 1);
699
+ expect(mergedPair?.strategyData?.decoded?.triggerData?.spoke).to.equal(spoke2);
700
+ expect(loneBoost?.subId).to.equal(1);
701
+ });
662
702
  });
663
703
  });
@@ -129,9 +129,20 @@ export default class StrategiesAutomation extends Automation {
129
129
  && (
130
130
  s.protocol.id !== ProtocolIdentifiers.StrategiesAutomation.MorphoBlue // merge morpho blue with the same marketId
131
131
  || s.strategyData.decoded.triggerData.marketId.toLowerCase() === current.strategyData.decoded.triggerData.marketId.toLowerCase()
132
+ )
133
+ && (
134
+ s.protocol.id !== ProtocolIdentifiers.StrategiesAutomation.AaveV4
135
+ || this._aaveV4MergeSpokesMatch(s, current)
132
136
  );
133
137
  }
134
138
 
139
+ /** Repay/boost leverage pairs must not merge across different Aave V4 spokes. */
140
+ private _aaveV4MergeSpokesMatch(s: Position.Automated, current: Position.Automated): boolean {
141
+ const a = s.strategyData?.decoded?.triggerData?.spoke as EthereumAddress | undefined;
142
+ const b = current.strategyData?.decoded?.triggerData?.spoke as EthereumAddress | undefined;
143
+ return !!a && !!b && a.toLowerCase() === b.toLowerCase();
144
+ }
145
+
135
146
  protected mergeSubs(_subscriptions:(Position.Automated | null)[]) {
136
147
  const mergeBase = _subscriptions.filter(s => isDefined(s) && isDefined(s.specific.mergeWithId)) as Position.Automated[];
137
148
  const mergeExtension = _subscriptions.filter(s => isDefined(s) && isDefined(s.specific.mergeId)) as Position.Automated[];