@defisaver/positions-sdk 2.1.142-dev → 2.1.143

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 (61) hide show
  1. package/cjs/aaveV3/merkl.js +4 -7
  2. package/cjs/aaveV4/merkl.js +5 -6
  3. package/cjs/claiming/aaveV3.d.ts +2 -1
  4. package/cjs/claiming/aaveV3.js +13 -4
  5. package/cjs/compoundV3/merkl.js +4 -6
  6. package/cjs/fluid/index.d.ts +9 -1
  7. package/cjs/fluid/index.js +10 -4
  8. package/cjs/fluid/merkl.d.ts +7 -4
  9. package/cjs/fluid/merkl.js +22 -16
  10. package/cjs/helpers/fluidHelpers/index.d.ts +3 -1
  11. package/cjs/helpers/fluidHelpers/index.js +37 -4
  12. package/cjs/morphoBlue/index.d.ts +1 -1
  13. package/cjs/morphoBlue/index.js +2 -2
  14. package/cjs/morphoBlue/merkl.d.ts +6 -4
  15. package/cjs/morphoBlue/merkl.js +17 -16
  16. package/cjs/portfolio/index.js +5 -5
  17. package/cjs/services/merkl.d.ts +6 -0
  18. package/cjs/services/merkl.js +39 -0
  19. package/cjs/types/claiming.d.ts +12 -1
  20. package/cjs/types/claiming.js +2 -0
  21. package/cjs/types/common.d.ts +4 -0
  22. package/cjs/types/common.js +5 -1
  23. package/cjs/types/fluid.d.ts +2 -0
  24. package/esm/aaveV3/merkl.js +5 -8
  25. package/esm/aaveV4/merkl.js +5 -6
  26. package/esm/claiming/aaveV3.d.ts +2 -1
  27. package/esm/claiming/aaveV3.js +12 -4
  28. package/esm/compoundV3/merkl.js +5 -7
  29. package/esm/fluid/index.d.ts +9 -1
  30. package/esm/fluid/index.js +9 -3
  31. package/esm/fluid/merkl.d.ts +7 -4
  32. package/esm/fluid/merkl.js +19 -15
  33. package/esm/helpers/fluidHelpers/index.d.ts +3 -1
  34. package/esm/helpers/fluidHelpers/index.js +38 -6
  35. package/esm/morphoBlue/index.d.ts +1 -1
  36. package/esm/morphoBlue/index.js +1 -1
  37. package/esm/morphoBlue/merkl.d.ts +6 -4
  38. package/esm/morphoBlue/merkl.js +16 -15
  39. package/esm/portfolio/index.js +6 -6
  40. package/esm/services/merkl.d.ts +6 -0
  41. package/esm/services/merkl.js +35 -0
  42. package/esm/types/claiming.d.ts +12 -1
  43. package/esm/types/claiming.js +2 -0
  44. package/esm/types/common.d.ts +4 -0
  45. package/esm/types/common.js +4 -0
  46. package/esm/types/fluid.d.ts +2 -0
  47. package/package.json +1 -1
  48. package/src/aaveV3/merkl.ts +5 -8
  49. package/src/aaveV4/merkl.ts +5 -5
  50. package/src/claiming/aaveV3.ts +19 -7
  51. package/src/compoundV3/merkl.ts +5 -6
  52. package/src/fluid/index.ts +9 -3
  53. package/src/fluid/merkl.ts +18 -13
  54. package/src/helpers/fluidHelpers/index.ts +68 -6
  55. package/src/morphoBlue/index.ts +1 -1
  56. package/src/morphoBlue/merkl.ts +16 -15
  57. package/src/portfolio/index.ts +6 -6
  58. package/src/services/merkl.ts +31 -0
  59. package/src/types/claiming.ts +13 -0
  60. package/src/types/common.ts +5 -0
  61. package/src/types/fluid.ts +3 -1
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getMerkleCampaigns = exports.formatAaveAsset = exports.getAaveUnderlyingSymbol = void 0;
13
13
  const moneymarket_1 = require("../moneymarket");
14
+ const merkl_1 = require("../services/merkl");
14
15
  const utils_1 = require("../services/utils");
15
16
  const types_1 = require("../types");
16
17
  const getAaveUnderlyingSymbol = (_symbol = '') => {
@@ -40,14 +41,10 @@ const formatAaveAsset = (_symbol) => {
40
41
  exports.formatAaveAsset = formatAaveAsset;
41
42
  const getMerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
42
43
  try {
43
- // status/items narrow the query because Merkl paginates at 20 items by default — an
44
- // unfiltered query silently drops live campaigns once the protocol has enough opportunities
45
- const res = yield fetch('https://fe.defisaver.com/api/merkl/opportunities?mainProtocolId=aave&status=LIVE&items=100', {
46
- signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
44
+ const opportunities = yield (0, merkl_1.fetchAllMerklOpportunities)({
45
+ mainProtocolId: 'aave',
46
+ status: types_1.OpportunityStatus.LIVE,
47
47
  });
48
- if (!res.ok)
49
- throw new Error('Failed to fetch Merkle campaigns');
50
- const opportunities = yield res.json();
51
48
  const relevantOpportunities = opportunities
52
49
  .filter((o) => o.chainId === chainId)
53
50
  .filter((o) => o.status === types_1.OpportunityStatus.LIVE);
@@ -11,7 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.attachAaveV4MerklIncentives = exports.getAaveV4MerkleCampaigns = exports.buildAaveV4MerklRewardMap = void 0;
13
13
  const moneymarket_1 = require("../moneymarket");
14
- const utils_1 = require("../services/utils");
14
+ const merkl_1 = require("../services/merkl");
15
15
  const types_1 = require("../types");
16
16
  /**
17
17
  * Merkl tags Aave V4 reward campaigns by scope via the `type` field:
@@ -67,12 +67,11 @@ const buildAaveV4MerklRewardMap = (opportunities, chainId) => {
67
67
  exports.buildAaveV4MerklRewardMap = buildAaveV4MerklRewardMap;
68
68
  const getAaveV4MerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
69
69
  try {
70
- const res = yield fetch('https://fe.defisaver.com/api/merkl/opportunities?mainProtocolId=aave&type=AAVE_V4_HUB_SUPPLY,AAVE_V4_HUB_BORROW,AAVE_V4_SPOKE_SUPPLY,AAVE_V4_SPOKE_BORROW&status=LIVE&items=100', {
71
- signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
70
+ const opportunities = yield (0, merkl_1.fetchAllMerklOpportunities)({
71
+ mainProtocolId: 'aave',
72
+ type: 'AAVE_V4_HUB_SUPPLY,AAVE_V4_HUB_BORROW,AAVE_V4_SPOKE_SUPPLY,AAVE_V4_SPOKE_BORROW',
73
+ status: types_1.OpportunityStatus.LIVE,
72
74
  });
73
- if (!res.ok)
74
- throw new Error('Failed to fetch Aave V4 Merkle campaigns');
75
- const opportunities = yield res.json();
76
75
  return (0, exports.buildAaveV4MerklRewardMap)(opportunities, chainId);
77
76
  }
78
77
  catch (e) {
@@ -1,5 +1,6 @@
1
1
  import { Client } from 'viem';
2
2
  import { EthAddress, NetworkNumber } from '../types';
3
- import { ClaimableToken } from '../types/claiming';
3
+ import { ClaimableToken, MerklRewardsClaimableToken } from '../types/claiming';
4
4
  export declare function getUnclaimedRewardsForAllMarkets(provider: Client, network: NetworkNumber, walletAddress: EthAddress, marketAddress: EthAddress): Promise<ClaimableToken[]>;
5
+ export declare function getMerklUnclaimedRewards(account: EthAddress, network: NetworkNumber): Promise<MerklRewardsClaimableToken[]>;
5
6
  export declare function getMeritUnclaimedRewards(account: EthAddress, network: NetworkNumber): Promise<ClaimableToken[]>;
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.getUnclaimedRewardsForAllMarkets = getUnclaimedRewardsForAllMarkets;
16
+ exports.getMerklUnclaimedRewards = getMerklUnclaimedRewards;
16
17
  exports.getMeritUnclaimedRewards = getMeritUnclaimedRewards;
17
18
  const decimal_js_1 = __importDefault(require("decimal.js"));
18
19
  const claiming_1 = require("../types/claiming");
@@ -95,7 +96,7 @@ function getUnclaimedRewardsForAllMarkets(provider, network, walletAddress, mark
95
96
  return mapAaveRewardsToClaimableTokens(Object.values(totalUnclaimedPerRewardToken), marketAddress, walletAddress);
96
97
  });
97
98
  }
98
- function getMeritUnclaimedRewards(account, network) {
99
+ function getMerklUnclaimedRewards(account, network) {
99
100
  return __awaiter(this, void 0, void 0, function* () {
100
101
  let data;
101
102
  try {
@@ -103,7 +104,7 @@ function getMeritUnclaimedRewards(account, network) {
103
104
  data = yield res.json();
104
105
  }
105
106
  catch (error) {
106
- console.error('External API Failure: Aave Merit', error);
107
+ console.error('External API Failure: Merkl rewards', error);
107
108
  data = [];
108
109
  }
109
110
  const claimableTokens = [];
@@ -121,12 +122,12 @@ function getMeritUnclaimedRewards(account, network) {
121
122
  return;
122
123
  const unclaimed = (0, utils_1.getEthAmountForDecimals)(unclaimedAmount, token.decimals);
123
124
  claimableTokens.push({
124
- claimType: claiming_1.ClaimType.AAVE_MERIT_REWARDS,
125
+ claimType: claiming_1.ClaimType.MERKL_REWARDS,
125
126
  amount: unclaimed,
126
127
  symbol: token.symbol,
127
128
  tokenAddress: token.address,
128
129
  walletAddress: account,
129
- label: 'AAVE Merit Rewards',
130
+ label: 'Merkl Rewards',
130
131
  underlyingSymbol: (0, aaveHelpers_1.getAaveUnderlyingSymbol)(token.symbol),
131
132
  additionalClaimFields: {
132
133
  accumulated: amount,
@@ -140,3 +141,11 @@ function getMeritUnclaimedRewards(account, network) {
140
141
  return claimableTokens;
141
142
  });
142
143
  }
144
+ function getMeritUnclaimedRewards(account, network) {
145
+ return __awaiter(this, void 0, void 0, function* () {
146
+ const rewards = yield getMerklUnclaimedRewards(account, network);
147
+ return rewards
148
+ .filter(reward => reward.symbol.startsWith('a'))
149
+ .map(reward => (Object.assign(Object.assign({}, reward), { claimType: claiming_1.ClaimType.AAVE_MERIT_REWARDS, label: 'AAVE Merit Rewards' })));
150
+ });
151
+ }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.attachCompoundV3MerklIncentives = exports.getCompoundV3MerklOpportunities = void 0;
13
13
  const tokens_1 = require("@defisaver/tokens");
14
14
  const moneymarket_1 = require("../moneymarket");
15
+ const merkl_1 = require("../services/merkl");
15
16
  const utils_1 = require("../services/utils");
16
17
  const types_1 = require("../types");
17
18
  /**
@@ -24,13 +25,10 @@ const types_1 = require("../types");
24
25
  */
25
26
  const getCompoundV3MerklOpportunities = () => __awaiter(void 0, void 0, void 0, function* () {
26
27
  try {
27
- const res = yield fetch('https://fe.defisaver.com/api/merkl/opportunities?mainProtocolId=compound-v3&status=LIVE&items=100', {
28
- signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
28
+ return yield (0, merkl_1.fetchAllMerklOpportunities)({
29
+ mainProtocolId: 'compound-v3',
30
+ status: types_1.OpportunityStatus.LIVE,
29
31
  });
30
- if (!res.ok)
31
- throw new Error('Failed to fetch Compound V3 Merkl campaigns');
32
- const data = yield res.json();
33
- return Array.isArray(data) ? data : [];
34
32
  }
35
33
  catch (e) {
36
34
  console.error('Failed to fetch Compound V3 Merkl campaigns', e);
@@ -1,7 +1,7 @@
1
1
  import { Client, PublicClient } from 'viem';
2
2
  import { EthAddress, EthereumProvider, NetworkNumber } from '../types/common';
3
3
  import { FluidAssetsData, FluidMarketData, FluidMarketInfo, FluidUsedAssets, FluidVaultData, InnerFluidMarketData } from '../types';
4
- export { FLUID_MERKL_OPPORTUNITY_TYPES, buildFluidMerklRewardMap, getFluidMerklCampaigns, attachFluidMerklIncentives, } from './merkl';
4
+ export { FluidMerklOpportunityType, buildFluidMerklRewardMap, getFluidMerklCampaigns, attachFluidMerklIncentives, } from './merkl';
5
5
  export declare const EMPTY_USED_ASSET: {
6
6
  isSupplied: boolean;
7
7
  isBorrowed: boolean;
@@ -22,6 +22,8 @@ export declare const EMPTY_FLUID_DATA: {
22
22
  minRatio: string;
23
23
  netApy: string;
24
24
  incentiveUsd: string;
25
+ merklSupplyIncentives: never[];
26
+ merklBorrowIncentives: never[];
25
27
  totalInterestUsd: string;
26
28
  isSubscribedToAutomation: boolean;
27
29
  automationResubscribeRequired: boolean;
@@ -127,6 +129,8 @@ export declare const _getUserPositions: (provider: PublicClient, network: Networ
127
129
  leftToBorrowUsd: string;
128
130
  netApy: string;
129
131
  incentiveUsd: string;
132
+ merklSupplyIncentives: import("../types").IncentiveData[];
133
+ merklBorrowIncentives: import("../types").IncentiveData[];
130
134
  ratio: string;
131
135
  collRatio: string;
132
136
  minRatio: string;
@@ -159,6 +163,8 @@ export declare const getUserPositions: (provider: EthereumProvider, network: Net
159
163
  leftToBorrowUsd: string;
160
164
  netApy: string;
161
165
  incentiveUsd: string;
166
+ merklSupplyIncentives: import("../types").IncentiveData[];
167
+ merklBorrowIncentives: import("../types").IncentiveData[];
162
168
  ratio: string;
163
169
  collRatio: string;
164
170
  minRatio: string;
@@ -191,6 +197,8 @@ export declare const _getUserPositionsPortfolio: (provider: PublicClient, networ
191
197
  leftToBorrowUsd: string;
192
198
  netApy: string;
193
199
  incentiveUsd: string;
200
+ merklSupplyIncentives: import("../types").IncentiveData[];
201
+ merklBorrowIncentives: import("../types").IncentiveData[];
194
202
  ratio: string;
195
203
  collRatio: string;
196
204
  minRatio: string;
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports._getUserPositionsPortfolio = exports.getUserPositions = exports._getUserPositions = exports.getAllUserEarnPositionsWithFTokens = exports._getAllUserEarnPositionsWithFTokens = exports.getFluidDepositData = exports._getFluidDepositData = exports.getFluidTokenData = exports._getFluidTokenData = exports.getAllFluidMarketDataChunked = exports._getAllFluidMarketDataChunked = exports.getFluidPositionWithMarket = exports._getFluidPositionWithMarket = exports.getFluidPosition = exports._getFluidPosition = exports.getFluidVaultIdsForUser = exports._getFluidVaultIdsForUser = exports.getFluidMarketData = exports._getFluidMarketData = exports.EMPTY_FLUID_DATA = exports.EMPTY_USED_ASSET = exports.attachFluidMerklIncentives = exports.getFluidMerklCampaigns = exports.buildFluidMerklRewardMap = exports.FLUID_MERKL_OPPORTUNITY_TYPES = void 0;
15
+ exports._getUserPositionsPortfolio = exports.getUserPositions = exports._getUserPositions = exports.getAllUserEarnPositionsWithFTokens = exports._getAllUserEarnPositionsWithFTokens = exports.getFluidDepositData = exports._getFluidDepositData = exports.getFluidTokenData = exports._getFluidTokenData = exports.getAllFluidMarketDataChunked = exports._getAllFluidMarketDataChunked = exports.getFluidPositionWithMarket = exports._getFluidPositionWithMarket = exports.getFluidPosition = exports._getFluidPosition = exports.getFluidVaultIdsForUser = exports._getFluidVaultIdsForUser = exports.getFluidMarketData = exports._getFluidMarketData = exports.EMPTY_FLUID_DATA = exports.EMPTY_USED_ASSET = exports.attachFluidMerklIncentives = exports.getFluidMerklCampaigns = exports.buildFluidMerklRewardMap = exports.FluidMerklOpportunityType = void 0;
16
16
  const decimal_js_1 = __importDefault(require("decimal.js"));
17
17
  const tokens_1 = require("@defisaver/tokens");
18
18
  const common_1 = require("../types/common");
@@ -27,7 +27,7 @@ const staking_1 = require("../staking");
27
27
  const viem_1 = require("../services/viem");
28
28
  const merkl_1 = require("./merkl");
29
29
  var merkl_2 = require("./merkl");
30
- Object.defineProperty(exports, "FLUID_MERKL_OPPORTUNITY_TYPES", { enumerable: true, get: function () { return merkl_2.FLUID_MERKL_OPPORTUNITY_TYPES; } });
30
+ Object.defineProperty(exports, "FluidMerklOpportunityType", { enumerable: true, get: function () { return merkl_2.FluidMerklOpportunityType; } });
31
31
  Object.defineProperty(exports, "buildFluidMerklRewardMap", { enumerable: true, get: function () { return merkl_2.buildFluidMerklRewardMap; } });
32
32
  Object.defineProperty(exports, "getFluidMerklCampaigns", { enumerable: true, get: function () { return merkl_2.getFluidMerklCampaigns; } });
33
33
  Object.defineProperty(exports, "attachFluidMerklIncentives", { enumerable: true, get: function () { return merkl_2.attachFluidMerklIncentives; } });
@@ -922,6 +922,8 @@ exports.EMPTY_FLUID_DATA = {
922
922
  minRatio: '0',
923
923
  netApy: '0',
924
924
  incentiveUsd: '0',
925
+ merklSupplyIncentives: [],
926
+ merklBorrowIncentives: [],
925
927
  totalInterestUsd: '0',
926
928
  isSubscribedToAutomation: false,
927
929
  automationResubscribeRequired: false,
@@ -1391,8 +1393,12 @@ const _getUserPositionsPortfolio = (provider, network, user) => __awaiter(void 0
1391
1393
  tokens.push('ETH');
1392
1394
  if (!tokens.includes('WBTC'))
1393
1395
  tokens.push('WBTC');
1394
- const tokenPrices = yield getTokensPricesForPortfolio(tokens, provider, network);
1395
- const parsedMarketData = (yield Promise.all(data[1].map((vaultData) => __awaiter(void 0, void 0, void 0, function* () { return parseMarketData(provider, vaultData, network, tokenPrices); }))));
1396
+ const [tokenPrices, merklCampaigns] = yield Promise.all([
1397
+ getTokensPricesForPortfolio(tokens, provider, network),
1398
+ (0, merkl_1.getFluidMerklCampaigns)(network),
1399
+ ]);
1400
+ const parsedMarketData = (yield Promise.all(data[1].map((vaultData) => __awaiter(void 0, void 0, void 0, function* () { return parseMarketData(provider, vaultData, network, tokenPrices); }))))
1401
+ .map(marketData => (marketData ? (0, merkl_1.attachFluidMerklIncentives)(marketData, merklCampaigns) : marketData));
1396
1402
  const userData = data[0].map((position, i) => (parsedMarketData[i] && Object.assign({}, parseUserData(position, parsedMarketData[i]))));
1397
1403
  return parsedMarketData.map((market, i) => ({
1398
1404
  marketData: market,
@@ -1,3 +1,4 @@
1
+ import memoize from 'memoizee';
1
2
  import { FluidMarketData, FluidMerklRewardMap, MerklOpportunity, NetworkNumber } from '../types';
2
3
  /**
3
4
  * Merkl tags Fluid vault-scoped reward campaigns via the opportunity `type` field:
@@ -13,14 +14,16 @@ import { FluidMarketData, FluidMerklRewardMap, MerklOpportunity, NetworkNumber }
13
14
  * ids apply unconditionally, mirroring Aave V3. Whitelist-gated campaigns only accrue to
14
15
  * whitelisted addresses, so they are skipped rather than advertised to every user.
15
16
  */
16
- export declare const FLUID_MERKL_OPPORTUNITY_TYPES: readonly ["FLUIDVAULT_COLLATERAL", "FLUIDVAULT_BORROW"];
17
+ export declare enum FluidMerklOpportunityType {
18
+ Collateral = "FLUIDVAULT_COLLATERAL",
19
+ Borrow = "FLUIDVAULT_BORROW"
20
+ }
17
21
  export declare const buildFluidMerklRewardMap: (opportunities: MerklOpportunity[], chainId: NetworkNumber) => FluidMerklRewardMap;
18
22
  /**
19
23
  * Fetches live vault-scoped Fluid campaigns for the chain, keyed by vault address. Never throws —
20
- * on any failure it returns an empty map, so Merkl being down can't break market data. The query
21
- * is narrowed by `type=` and capped at `items=100` because Merkl paginates at 20 items by default.
24
+ * on any failure it returns an empty map, so Merkl being down can't break market data.
22
25
  */
23
- export declare const getFluidMerklCampaigns: (chainId: NetworkNumber) => Promise<FluidMerklRewardMap>;
26
+ export declare const getFluidMerklCampaigns: ((chainId: NetworkNumber) => Promise<FluidMerklRewardMap>) & memoize.Memoized<(chainId: NetworkNumber) => Promise<FluidMerklRewardMap>>;
24
27
  /**
25
28
  * Appends the vault's Merkl campaigns to its assets' incentive arrays — supply rewards on every
26
29
  * suppliable asset and borrow rewards on every borrowable one. Smart collateral/debt vaults hold
@@ -8,10 +8,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.attachFluidMerklIncentives = exports.getFluidMerklCampaigns = exports.buildFluidMerklRewardMap = exports.FLUID_MERKL_OPPORTUNITY_TYPES = void 0;
15
+ exports.attachFluidMerklIncentives = exports.getFluidMerklCampaigns = exports.buildFluidMerklRewardMap = exports.FluidMerklOpportunityType = void 0;
16
+ const memoizee_1 = __importDefault(require("memoizee"));
13
17
  const moneymarket_1 = require("../moneymarket");
14
- const utils_1 = require("../services/utils");
18
+ const merkl_1 = require("../services/merkl");
15
19
  const types_1 = require("../types");
16
20
  /**
17
21
  * Merkl tags Fluid vault-scoped reward campaigns via the opportunity `type` field:
@@ -27,7 +31,11 @@ const types_1 = require("../types");
27
31
  * ids apply unconditionally, mirroring Aave V3. Whitelist-gated campaigns only accrue to
28
32
  * whitelisted addresses, so they are skipped rather than advertised to every user.
29
33
  */
30
- exports.FLUID_MERKL_OPPORTUNITY_TYPES = ['FLUIDVAULT_COLLATERAL', 'FLUIDVAULT_BORROW'];
34
+ var FluidMerklOpportunityType;
35
+ (function (FluidMerklOpportunityType) {
36
+ FluidMerklOpportunityType["Collateral"] = "FLUIDVAULT_COLLATERAL";
37
+ FluidMerklOpportunityType["Borrow"] = "FLUIDVAULT_BORROW";
38
+ })(FluidMerklOpportunityType || (exports.FluidMerklOpportunityType = FluidMerklOpportunityType = {}));
31
39
  // '0x' + 20-byte vault address; conditional campaigns append a marker after it
32
40
  const VAULT_ADDRESS_LENGTH = 42;
33
41
  const buildMerklIncentive = (opportunity) => {
@@ -37,6 +45,7 @@ const buildMerklIncentive = (opportunity) => {
37
45
  apy: (0, moneymarket_1.aprToApy)(opportunity.apr),
38
46
  token,
39
47
  incentiveKind: types_1.IncentiveKind.Reward,
48
+ source: types_1.IncentiveSource.Merkl,
40
49
  description: `Eligible for ${token} rewards through Merkl.${opportunity.description ? `\n${opportunity.description}` : ''}`,
41
50
  eligibilityId: opportunity.identifier,
42
51
  };
@@ -46,7 +55,7 @@ const buildFluidMerklRewardMap = (opportunities, chainId) => {
46
55
  opportunities
47
56
  .filter((o) => o.chainId === chainId)
48
57
  .filter((o) => o.status === types_1.OpportunityStatus.LIVE)
49
- .filter((o) => exports.FLUID_MERKL_OPPORTUNITY_TYPES.includes(o.type))
58
+ .filter((o) => Object.values(FluidMerklOpportunityType).includes(o.type))
50
59
  .filter((o) => { var _a; return !((_a = o.identifier) === null || _a === void 0 ? void 0 : _a.includes('WHITELIST')); })
51
60
  .forEach((o) => {
52
61
  var _a;
@@ -55,32 +64,29 @@ const buildFluidMerklRewardMap = (opportunities, chainId) => {
55
64
  return;
56
65
  if (!result[vaultAddress])
57
66
  result[vaultAddress] = { supply: [], borrow: [] };
58
- result[vaultAddress][o.type === 'FLUIDVAULT_BORROW' ? 'borrow' : 'supply'].push(buildMerklIncentive(o));
67
+ result[vaultAddress][o.type === FluidMerklOpportunityType.Borrow ? 'borrow' : 'supply'].push(buildMerklIncentive(o));
59
68
  });
60
69
  return result;
61
70
  };
62
71
  exports.buildFluidMerklRewardMap = buildFluidMerklRewardMap;
63
72
  /**
64
73
  * Fetches live vault-scoped Fluid campaigns for the chain, keyed by vault address. Never throws —
65
- * on any failure it returns an empty map, so Merkl being down can't break market data. The query
66
- * is narrowed by `type=` and capped at `items=100` because Merkl paginates at 20 items by default.
74
+ * on any failure it returns an empty map, so Merkl being down can't break market data.
67
75
  */
68
- const getFluidMerklCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
76
+ exports.getFluidMerklCampaigns = (0, memoizee_1.default)((chainId) => __awaiter(void 0, void 0, void 0, function* () {
69
77
  try {
70
- const res = yield fetch(`https://fe.defisaver.com/api/merkl/opportunities?mainProtocolId=fluid&type=${exports.FLUID_MERKL_OPPORTUNITY_TYPES.join(',')}&status=LIVE&items=100`, {
71
- signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
78
+ const opportunities = yield (0, merkl_1.fetchAllMerklOpportunities)({
79
+ mainProtocolId: 'fluid',
80
+ type: Object.values(FluidMerklOpportunityType).join(','),
81
+ status: types_1.OpportunityStatus.LIVE,
72
82
  });
73
- if (!res.ok)
74
- throw new Error('Failed to fetch Fluid Merkl campaigns');
75
- const opportunities = yield res.json();
76
- return (0, exports.buildFluidMerklRewardMap)(Array.isArray(opportunities) ? opportunities : [], chainId);
83
+ return (0, exports.buildFluidMerklRewardMap)(opportunities, chainId);
77
84
  }
78
85
  catch (e) {
79
86
  console.error('Failed to fetch Fluid Merkl campaigns', e);
80
87
  return {};
81
88
  }
82
- });
83
- exports.getFluidMerklCampaigns = getFluidMerklCampaigns;
89
+ }), { promise: true, maxAge: 60 * 1000 });
84
90
  /**
85
91
  * Appends the vault's Merkl campaigns to its assets' incentive arrays — supply rewards on every
86
92
  * suppliable asset and borrow rewards on every borrowable one. Smart collateral/debt vaults hold
@@ -1,4 +1,6 @@
1
- import { FluidAggregatedVaultData, FluidAssetData, FluidAssetsData, FluidDexBorrowDataStructOutput, FluidDexSupplyDataStructOutput, FluidUsedAsset, FluidUsedAssets, InnerFluidMarketData } from '../../types';
1
+ import { FluidAggregatedVaultData, FluidAssetData, FluidAssetsData, FluidDexBorrowDataStructOutput, FluidDexSupplyDataStructOutput, FluidUsedAsset, FluidUsedAssets, IncentiveData, InnerFluidMarketData } from '../../types';
2
+ import { IncentiveSide } from '../../types/common';
3
+ export declare const getUniqueFluidMerklIncentives: (assetsData: FluidAssetsData, side: IncentiveSide) => IncentiveData[];
2
4
  export declare const getFluidAggregatedData: ({ usedAssets, assetsData, marketData, }: {
3
5
  usedAssets: FluidUsedAssets;
4
6
  marketData: InnerFluidMarketData;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.mergeUsedAssets = exports.EMPTY_USED_ASSET = exports.mergeAssetData = exports.parseDexBorrowData = exports.parseDexSupplyData = exports.getFluidAggregatedData = void 0;
6
+ exports.mergeUsedAssets = exports.EMPTY_USED_ASSET = exports.mergeAssetData = exports.parseDexBorrowData = exports.parseDexSupplyData = exports.getFluidAggregatedData = exports.getUniqueFluidMerklIncentives = void 0;
7
7
  const decimal_js_1 = __importDefault(require("decimal.js"));
8
8
  const tokens_1 = require("@defisaver/tokens");
9
9
  const types_1 = require("../../types");
@@ -11,13 +11,38 @@ const moneymarket_1 = require("../../moneymarket");
11
11
  const staking_1 = require("../../staking");
12
12
  const common_1 = require("../../types/common");
13
13
  const utils_1 = require("../../services/utils");
14
- const calculateNetApyDex = ({ marketData, suppliedUsd, borrowedUsd }) => {
14
+ const getUniqueFluidMerklIncentives = (assetsData, side) => {
15
+ const field = side === common_1.IncentiveSide.Supply ? 'supplyIncentives' : 'borrowIncentives';
16
+ const incentives = Object.values(assetsData)
17
+ .flatMap(asset => asset[field])
18
+ .filter(incentive => incentive.source === types_1.IncentiveSource.Merkl);
19
+ return [...new Map(incentives.map(incentive => [
20
+ [incentive.eligibilityId, incentive.token, incentive.apy, incentive.description].join('|'),
21
+ incentive,
22
+ ])).values()];
23
+ };
24
+ exports.getUniqueFluidMerklIncentives = getUniqueFluidMerklIncentives;
25
+ const getMerklIncentiveInterest = (incentives, principal, usedAssets) => incentives.reduce((total, { apy, eligibilityId }) => {
26
+ const eligibilityCheck = eligibilityId ? staking_1.EligibilityMapping[eligibilityId] : null;
27
+ const { isEligible, eligibleUSDAmount } = eligibilityCheck
28
+ ? eligibilityCheck(usedAssets, undefined)
29
+ : { isEligible: true, eligibleUSDAmount: principal };
30
+ const incentiveInterest = isEligible ? (0, staking_1.calculateInterestEarned)(eligibleUSDAmount, apy, 'year', true) : 0;
31
+ return new decimal_js_1.default(total).add(incentiveInterest).toString();
32
+ }, '0');
33
+ const calculateNetApyDex = ({ marketData, assetsData, usedAssets, suppliedUsd, borrowedUsd, }) => {
15
34
  const { borrowRate, supplyRate, incentiveBorrowRate, incentiveSupplyRate, tradingBorrowRate, tradingSupplyRate, } = marketData;
16
35
  const totalBorrowRate = new decimal_js_1.default(borrowRate).minus(tradingBorrowRate || '0').toString();
17
36
  const totalSupplyRate = new decimal_js_1.default(supplyRate).add(tradingSupplyRate || '0').toString();
18
37
  const borrowIncentive = new decimal_js_1.default(incentiveBorrowRate || '0').mul(borrowedUsd).div(100).toString();
19
38
  const supplyIncentive = new decimal_js_1.default(incentiveSupplyRate || '0').mul(suppliedUsd).div(100).toString();
20
- const incentiveUsd = new decimal_js_1.default(supplyIncentive).minus(borrowIncentive).toString();
39
+ const merklSupplyIncentive = getMerklIncentiveInterest((0, exports.getUniqueFluidMerklIncentives)(assetsData, common_1.IncentiveSide.Supply), suppliedUsd, usedAssets);
40
+ const merklBorrowIncentive = getMerklIncentiveInterest((0, exports.getUniqueFluidMerklIncentives)(assetsData, common_1.IncentiveSide.Borrow), borrowedUsd, usedAssets);
41
+ const incentiveUsd = new decimal_js_1.default(supplyIncentive)
42
+ .minus(borrowIncentive)
43
+ .add(merklSupplyIncentive)
44
+ .add(merklBorrowIncentive)
45
+ .toString();
21
46
  const borrowInterest = new decimal_js_1.default(totalBorrowRate).mul(borrowedUsd).div(100).toString();
22
47
  const supplyInterest = new decimal_js_1.default(totalSupplyRate).mul(suppliedUsd).div(100).toString();
23
48
  const totalInterestUsd = new decimal_js_1.default(supplyInterest).add(incentiveUsd).minus(borrowInterest).toString();
@@ -38,7 +63,15 @@ const getFluidAggregatedData = ({ usedAssets, assetsData, marketData, }, supplyS
38
63
  ? (0, moneymarket_1.getAssetsTotal)(usedAssets, ({ isBorrowed }) => isBorrowed, ({ borrowedUsd }) => borrowedUsd)
39
64
  : new decimal_js_1.default(marketData.debtSharePrice).mul(borrowShares).toString();
40
65
  const isDex = [types_1.FluidVaultType.T2, types_1.FluidVaultType.T3, types_1.FluidVaultType.T4].includes(marketData.vaultType);
41
- const { netApy, incentiveUsd, totalInterestUsd } = isDex ? calculateNetApyDex({ marketData, suppliedUsd: payload.suppliedUsd, borrowedUsd: payload.borrowedUsd }) : (0, staking_1.calculateNetApy)({ usedAssets, assetsData: assetsData });
66
+ payload.merklSupplyIncentives = (0, exports.getUniqueFluidMerklIncentives)(assetsData, common_1.IncentiveSide.Supply);
67
+ payload.merklBorrowIncentives = (0, exports.getUniqueFluidMerklIncentives)(assetsData, common_1.IncentiveSide.Borrow);
68
+ const { netApy, incentiveUsd, totalInterestUsd } = isDex ? calculateNetApyDex({
69
+ marketData,
70
+ assetsData,
71
+ usedAssets,
72
+ suppliedUsd: payload.suppliedUsd,
73
+ borrowedUsd: payload.borrowedUsd,
74
+ }) : (0, staking_1.calculateNetApy)({ usedAssets, assetsData: assetsData });
42
75
  payload.netApy = netApy;
43
76
  payload.incentiveUsd = incentiveUsd;
44
77
  payload.totalInterestUsd = totalInterestUsd;
@@ -1,7 +1,7 @@
1
1
  import { Client } from 'viem';
2
2
  import { Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances } from '../types/common';
3
3
  import { MorphoBlueEarnData, MorphoBlueMarketData, MorphoBlueMarketInfo, MorphoBlueMarketRewards, MorphoBluePositionData } from '../types';
4
- export { MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES, addMorphoBlueMerklOpportunitiesToMarketInfo, getMorphoBlueMerklOpportunities, addMorphoBlueMerklRewardsToMarketInfo, } from './merkl';
4
+ export { MorphoBlueMerklOpportunityType, addMorphoBlueMerklOpportunitiesToMarketInfo, getMorphoBlueMerklOpportunities, addMorphoBlueMerklRewardsToMarketInfo, } from './merkl';
5
5
  export declare const addMorphoBlueRewardsToMarketInfo: (marketInfo: MorphoBlueMarketInfo, rewards: MorphoBlueMarketRewards) => MorphoBlueMarketInfo;
6
6
  export declare function _getMorphoBlueMarketData(provider: Client, network: NetworkNumber, selectedMarket: MorphoBlueMarketData): Promise<MorphoBlueMarketInfo>;
7
7
  export declare function _getMorphoBluePortfolioMarketData(provider: Client, network: NetworkNumber, selectedMarket: MorphoBlueMarketData): Promise<MorphoBlueMarketInfo>;
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.getMorphoBlueAccountBalances = exports._getMorphoBlueAccountBalances = exports.getMorphoEarnDataWithMarketInfo = exports.getMorphoBluePositionDataWithMarketInfo = exports.addMorphoBlueRewardsToMarketInfo = exports.addMorphoBlueMerklRewardsToMarketInfo = exports.getMorphoBlueMerklOpportunities = exports.addMorphoBlueMerklOpportunitiesToMarketInfo = exports.MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES = void 0;
15
+ exports.getMorphoBlueAccountBalances = exports._getMorphoBlueAccountBalances = exports.getMorphoEarnDataWithMarketInfo = exports.getMorphoBluePositionDataWithMarketInfo = exports.addMorphoBlueRewardsToMarketInfo = exports.addMorphoBlueMerklRewardsToMarketInfo = exports.getMorphoBlueMerklOpportunities = exports.addMorphoBlueMerklOpportunitiesToMarketInfo = exports.MorphoBlueMerklOpportunityType = void 0;
16
16
  exports._getMorphoBlueMarketData = _getMorphoBlueMarketData;
17
17
  exports._getMorphoBluePortfolioMarketData = _getMorphoBluePortfolioMarketData;
18
18
  exports.getMorphoBlueMarketData = getMorphoBlueMarketData;
@@ -33,7 +33,7 @@ const priceService_1 = require("../services/priceService");
33
33
  const viem_1 = require("../services/viem");
34
34
  const merkl_1 = require("./merkl");
35
35
  var merkl_2 = require("./merkl");
36
- Object.defineProperty(exports, "MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES", { enumerable: true, get: function () { return merkl_2.MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES; } });
36
+ Object.defineProperty(exports, "MorphoBlueMerklOpportunityType", { enumerable: true, get: function () { return merkl_2.MorphoBlueMerklOpportunityType; } });
37
37
  Object.defineProperty(exports, "addMorphoBlueMerklOpportunitiesToMarketInfo", { enumerable: true, get: function () { return merkl_2.addMorphoBlueMerklOpportunitiesToMarketInfo; } });
38
38
  Object.defineProperty(exports, "getMorphoBlueMerklOpportunities", { enumerable: true, get: function () { return merkl_2.getMorphoBlueMerklOpportunities; } });
39
39
  Object.defineProperty(exports, "addMorphoBlueMerklRewardsToMarketInfo", { enumerable: true, get: function () { return merkl_2.addMorphoBlueMerklRewardsToMarketInfo; } });
@@ -12,7 +12,11 @@ import { MerklOpportunity, MorphoBlueMarketData, MorphoBlueMarketInfo, NetworkNu
12
12
  * identifier (e.g. `0x54cf…c46WHITELIST_CAMPAIGN`); their rewards only accrue to whitelisted
13
13
  * addresses, so they are skipped rather than advertised to every user.
14
14
  */
15
- export declare const MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES: readonly ["MORPHOSUPPLY", "MORPHOCOLLATERAL", "MORPHOBORROW"];
15
+ export declare enum MorphoBlueMerklOpportunityType {
16
+ Supply = "MORPHOSUPPLY",
17
+ Collateral = "MORPHOCOLLATERAL",
18
+ Borrow = "MORPHOBORROW"
19
+ }
16
20
  /**
17
21
  * Appends the given live Merkl campaigns for the market to its `assetsData` incentive arrays
18
22
  * (collateral supply / loan supply / loan borrow). Existing Merkl incentives are replaced rather
@@ -21,9 +25,7 @@ export declare const MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES: readonly ["MORPHOSUPPL
21
25
  export declare const addMorphoBlueMerklOpportunitiesToMarketInfo: (marketInfo: MorphoBlueMarketInfo, selectedMarket: MorphoBlueMarketData, chainId: NetworkNumber, opportunities: MerklOpportunity[]) => MorphoBlueMarketInfo;
22
26
  /**
23
27
  * Fetches live market-scoped Morpho Blue campaigns for all chains. Never throws — on any failure
24
- * it returns an empty list, so Merkl being down can't break market data. The query is narrowed by
25
- * `type=` and capped at `items=100` because Merkl paginates at 20 items by default — an
26
- * unfiltered protocol query would silently drop campaigns once Morpho has enough opportunities.
28
+ * it returns an empty list, so Merkl being down can't break market data.
27
29
  */
28
30
  export declare const getMorphoBlueMerklOpportunities: () => Promise<MerklOpportunity[]>;
29
31
  /**
@@ -9,9 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.addMorphoBlueMerklRewardsToMarketInfo = exports.getMorphoBlueMerklOpportunities = exports.addMorphoBlueMerklOpportunitiesToMarketInfo = exports.MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES = void 0;
12
+ exports.addMorphoBlueMerklRewardsToMarketInfo = exports.getMorphoBlueMerklOpportunities = exports.addMorphoBlueMerklOpportunitiesToMarketInfo = exports.MorphoBlueMerklOpportunityType = void 0;
13
13
  const moneymarket_1 = require("../moneymarket");
14
- const utils_1 = require("../services/utils");
14
+ const merkl_1 = require("../services/merkl");
15
15
  const types_1 = require("../types");
16
16
  /**
17
17
  * Merkl tags Morpho Blue market-level reward campaigns via the opportunity `type` field:
@@ -26,7 +26,12 @@ const types_1 = require("../types");
26
26
  * identifier (e.g. `0x54cf…c46WHITELIST_CAMPAIGN`); their rewards only accrue to whitelisted
27
27
  * addresses, so they are skipped rather than advertised to every user.
28
28
  */
29
- exports.MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES = ['MORPHOSUPPLY', 'MORPHOCOLLATERAL', 'MORPHOBORROW'];
29
+ var MorphoBlueMerklOpportunityType;
30
+ (function (MorphoBlueMerklOpportunityType) {
31
+ MorphoBlueMerklOpportunityType["Supply"] = "MORPHOSUPPLY";
32
+ MorphoBlueMerklOpportunityType["Collateral"] = "MORPHOCOLLATERAL";
33
+ MorphoBlueMerklOpportunityType["Borrow"] = "MORPHOBORROW";
34
+ })(MorphoBlueMerklOpportunityType || (exports.MorphoBlueMerklOpportunityType = MorphoBlueMerklOpportunityType = {}));
30
35
  const MERKL_DESCRIPTION_MARKER = 'through Merkl';
31
36
  // '0x' + first 20 bytes of the market id
32
37
  const MARKET_ID_PREFIX_LENGTH = 42;
@@ -57,7 +62,7 @@ const addMorphoBlueMerklOpportunitiesToMarketInfo = (marketInfo, selectedMarket,
57
62
  var _a;
58
63
  return o.chainId === chainId
59
64
  && o.status === types_1.OpportunityStatus.LIVE
60
- && exports.MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES.includes(o.type)
65
+ && Object.values(MorphoBlueMerklOpportunityType).includes(o.type)
61
66
  // a suffixed identifier marks a whitelist-gated campaign — skip those
62
67
  && ((_a = o.identifier) === null || _a === void 0 ? void 0 : _a.length) === MARKET_ID_PREFIX_LENGTH
63
68
  && o.identifier.toLowerCase() === marketIdPrefix;
@@ -65,27 +70,23 @@ const addMorphoBlueMerklOpportunitiesToMarketInfo = (marketInfo, selectedMarket,
65
70
  if (!relevant.length)
66
71
  return marketInfo;
67
72
  const incentivesByType = (type) => relevant.filter((o) => o.type === type).map(buildMerklIncentive);
68
- const collateralSupply = incentivesByType('MORPHOCOLLATERAL');
69
- const loanSupply = incentivesByType('MORPHOSUPPLY');
70
- const loanBorrow = incentivesByType('MORPHOBORROW');
73
+ const collateralSupply = incentivesByType(MorphoBlueMerklOpportunityType.Collateral);
74
+ const loanSupply = incentivesByType(MorphoBlueMerklOpportunityType.Supply);
75
+ const loanBorrow = incentivesByType(MorphoBlueMerklOpportunityType.Borrow);
71
76
  return Object.assign(Object.assign({}, marketInfo), { assetsData: Object.assign(Object.assign({}, marketInfo.assetsData), { [marketInfo.collateralToken]: Object.assign(Object.assign({}, collateralAsset), { supplyIncentives: [...withoutMerklIncentives(collateralAsset.supplyIncentives), ...collateralSupply] }), [marketInfo.loanToken]: Object.assign(Object.assign({}, loanAsset), { supplyIncentives: [...withoutMerklIncentives(loanAsset.supplyIncentives), ...loanSupply], borrowIncentives: [...withoutMerklIncentives(loanAsset.borrowIncentives), ...loanBorrow] }) }) });
72
77
  };
73
78
  exports.addMorphoBlueMerklOpportunitiesToMarketInfo = addMorphoBlueMerklOpportunitiesToMarketInfo;
74
79
  /**
75
80
  * Fetches live market-scoped Morpho Blue campaigns for all chains. Never throws — on any failure
76
- * it returns an empty list, so Merkl being down can't break market data. The query is narrowed by
77
- * `type=` and capped at `items=100` because Merkl paginates at 20 items by default — an
78
- * unfiltered protocol query would silently drop campaigns once Morpho has enough opportunities.
81
+ * it returns an empty list, so Merkl being down can't break market data.
79
82
  */
80
83
  const getMorphoBlueMerklOpportunities = () => __awaiter(void 0, void 0, void 0, function* () {
81
84
  try {
82
- const res = yield fetch(`https://fe.defisaver.com/api/merkl/opportunities?mainProtocolId=morpho&type=${exports.MORPHO_BLUE_MERKL_OPPORTUNITY_TYPES.join(',')}&status=LIVE&items=100`, {
83
- signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
85
+ return yield (0, merkl_1.fetchAllMerklOpportunities)({
86
+ mainProtocolId: 'morpho',
87
+ type: Object.values(MorphoBlueMerklOpportunityType).join(','),
88
+ status: types_1.OpportunityStatus.LIVE,
84
89
  });
85
- if (!res.ok)
86
- throw new Error('Failed to fetch Morpho Blue Merkl campaigns');
87
- const data = yield res.json();
88
- return Array.isArray(data) ? data : [];
89
90
  }
90
91
  catch (e) {
91
92
  console.error('Failed to fetch Morpho Blue Merkl campaigns', e);
@@ -134,7 +134,7 @@ function getPortfolioData(provider_1, network_1, defaultProvider_1, addresses_1)
134
134
  },
135
135
  };
136
136
  rewardsData[address.toLowerCase()] = {
137
- aaveV3merit: {},
137
+ merkl: {},
138
138
  aaveV3: {},
139
139
  compV3: {},
140
140
  spark: {},
@@ -355,12 +355,12 @@ function getPortfolioData(provider_1, network_1, defaultProvider_1, addresses_1)
355
355
  }))).flat(),
356
356
  ...addresses.map((address) => __awaiter(this, void 0, void 0, function* () {
357
357
  try {
358
- const aaveMeritData = yield (0, aaveV3_2.getMeritUnclaimedRewards)(address, network);
359
- rewardsData[address.toLowerCase()].aaveV3merit = { error: '', data: aaveMeritData };
358
+ const merklData = yield (0, aaveV3_2.getMerklUnclaimedRewards)(address, network);
359
+ rewardsData[address.toLowerCase()].merkl = { error: '', data: merklData };
360
360
  }
361
361
  catch (error) {
362
- console.error(`Error fetching Aave V3 Merit rewards data for address ${address}:`, error);
363
- rewardsData[address.toLowerCase()].aaveV3merit = { error: `Error fetching Aave V3 Merit rewards data for address ${address}`, data: null };
362
+ console.error(`Error fetching Merkl rewards data for address ${address}:`, error);
363
+ rewardsData[address.toLowerCase()].merkl = { error: `Error fetching Merkl rewards data for address ${address}`, data: null };
364
364
  }
365
365
  })),
366
366
  ...aaveV3Markets.map(market => addresses.map((address) => __awaiter(this, void 0, void 0, function* () {
@@ -0,0 +1,6 @@
1
+ import { MerklOpportunity } from '../types';
2
+ /**
3
+ * Fetches every page matching the query. Merkl returns 20 opportunities by default, so omitting
4
+ * `items` and advancing `page` avoids imposing a client-side maximum on the result set.
5
+ */
6
+ export declare const fetchAllMerklOpportunities: (query: Record<string, string>) => Promise<MerklOpportunity[]>;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.fetchAllMerklOpportunities = void 0;
13
+ const utils_1 = require("./utils");
14
+ const MERKL_OPPORTUNITIES_URL = 'https://fe.defisaver.com/api/merkl/opportunities';
15
+ /**
16
+ * Fetches every page matching the query. Merkl returns 20 opportunities by default, so omitting
17
+ * `items` and advancing `page` avoids imposing a client-side maximum on the result set.
18
+ */
19
+ const fetchAllMerklOpportunities = (query) => __awaiter(void 0, void 0, void 0, function* () {
20
+ const opportunities = [];
21
+ let page = 0;
22
+ let pageOpportunities;
23
+ do {
24
+ const searchParams = new URLSearchParams(Object.assign(Object.assign({}, query), { page: page.toString() }));
25
+ const res = yield fetch(`${MERKL_OPPORTUNITIES_URL}?${searchParams}`, {
26
+ signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
27
+ });
28
+ if (!res.ok)
29
+ throw new Error(`Failed to fetch Merkl opportunities page ${page}`);
30
+ const data = yield res.json(); // eslint-disable-line no-await-in-loop
31
+ if (!Array.isArray(data))
32
+ throw new Error(`Invalid Merkl opportunities response on page ${page}`);
33
+ pageOpportunities = data;
34
+ opportunities.push(...pageOpportunities);
35
+ page += 1;
36
+ } while (pageOpportunities.length > 0);
37
+ return opportunities;
38
+ });
39
+ exports.fetchAllMerklOpportunities = fetchAllMerklOpportunities;