@defisaver/positions-sdk 2.1.141 → 2.1.142

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 (55) hide show
  1. package/cjs/aaveV3/merkl.js +10 -9
  2. package/cjs/aaveV4/merkl.js +5 -6
  3. package/cjs/compoundV3/index.d.ts +1 -0
  4. package/cjs/compoundV3/index.js +8 -2
  5. package/cjs/compoundV3/merkl.d.ts +16 -0
  6. package/cjs/compoundV3/merkl.js +77 -0
  7. package/cjs/fluid/index.d.ts +1 -0
  8. package/cjs/fluid/index.js +28 -8
  9. package/cjs/fluid/merkl.d.ts +31 -0
  10. package/cjs/fluid/merkl.js +99 -0
  11. package/cjs/morphoBlue/index.d.ts +1 -0
  12. package/cjs/morphoBlue/index.js +16 -10
  13. package/cjs/morphoBlue/merkl.d.ts +35 -0
  14. package/cjs/morphoBlue/merkl.js +102 -0
  15. package/cjs/services/merkl.d.ts +6 -0
  16. package/cjs/services/merkl.js +39 -0
  17. package/cjs/staking/eligibility.d.ts +4 -0
  18. package/cjs/staking/eligibility.js +11 -1
  19. package/cjs/types/common.d.ts +2 -1
  20. package/cjs/types/common.js +1 -0
  21. package/cjs/types/merkl.d.ts +8 -0
  22. package/esm/aaveV3/merkl.js +11 -10
  23. package/esm/aaveV4/merkl.js +5 -6
  24. package/esm/compoundV3/index.d.ts +1 -0
  25. package/esm/compoundV3/index.js +5 -1
  26. package/esm/compoundV3/merkl.d.ts +16 -0
  27. package/esm/compoundV3/merkl.js +72 -0
  28. package/esm/fluid/index.d.ts +1 -0
  29. package/esm/fluid/index.js +23 -7
  30. package/esm/fluid/merkl.d.ts +31 -0
  31. package/esm/fluid/merkl.js +93 -0
  32. package/esm/morphoBlue/index.d.ts +1 -0
  33. package/esm/morphoBlue/index.js +11 -9
  34. package/esm/morphoBlue/merkl.d.ts +35 -0
  35. package/esm/morphoBlue/merkl.js +96 -0
  36. package/esm/services/merkl.d.ts +6 -0
  37. package/esm/services/merkl.js +35 -0
  38. package/esm/staking/eligibility.d.ts +4 -0
  39. package/esm/staking/eligibility.js +9 -0
  40. package/esm/types/common.d.ts +2 -1
  41. package/esm/types/common.js +1 -0
  42. package/esm/types/merkl.d.ts +8 -0
  43. package/package.json +1 -1
  44. package/src/aaveV3/merkl.ts +7 -7
  45. package/src/aaveV4/merkl.ts +5 -5
  46. package/src/compoundV3/index.ts +6 -1
  47. package/src/compoundV3/merkl.ts +76 -0
  48. package/src/fluid/index.ts +29 -7
  49. package/src/fluid/merkl.ts +99 -0
  50. package/src/morphoBlue/index.ts +24 -9
  51. package/src/morphoBlue/merkl.ts +121 -0
  52. package/src/services/merkl.ts +31 -0
  53. package/src/staking/eligibility.ts +10 -0
  54. package/src/types/common.ts +1 -0
  55. package/src/types/merkl.ts +6 -0
@@ -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,21 +41,21 @@ 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
- const res = yield fetch('https://fe.defisaver.com/api/merkl/opportunities?mainProtocolId=aave', {
44
- signal: AbortSignal.timeout(utils_1.LONGER_TIMEOUT),
44
+ const opportunities = yield (0, merkl_1.fetchAllMerklOpportunities)({
45
+ mainProtocolId: 'aave',
46
+ status: types_1.OpportunityStatus.LIVE,
45
47
  });
46
- if (!res.ok)
47
- throw new Error('Failed to fetch Merkle campaigns');
48
- const opportunities = yield res.json();
49
48
  const relevantOpportunities = opportunities
50
49
  .filter((o) => o.chainId === chainId)
51
50
  .filter((o) => o.status === types_1.OpportunityStatus.LIVE);
52
51
  return relevantOpportunities.reduce((acc, opportunity) => {
53
- var _a, _b;
54
- const rewardToken = opportunity.rewardsRecord.breakdowns[0].token;
52
+ var _a, _b, _c, _d, _e;
53
+ const rewardToken = (_c = (_b = (_a = opportunity.rewardsRecord) === null || _a === void 0 ? void 0 : _a.breakdowns) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.token;
54
+ if (!rewardToken)
55
+ return acc;
55
56
  const description = `Eligible for ${(0, exports.formatAaveAsset)(rewardToken.symbol)} rewards through Merkl. ${opportunity.description ? `\n${opportunity.description}` : ''}`;
56
57
  if (opportunity.action === types_1.OpportunityAction.LEND && opportunity.explorerAddress) {
57
- const supplyAToken = (_a = opportunity.explorerAddress) === null || _a === void 0 ? void 0 : _a.toLowerCase();
58
+ const supplyAToken = (_d = opportunity.explorerAddress) === null || _d === void 0 ? void 0 : _d.toLowerCase();
58
59
  if (!acc[supplyAToken])
59
60
  acc[supplyAToken] = {};
60
61
  acc[supplyAToken].supply = {
@@ -66,7 +67,7 @@ const getMerkleCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, functi
66
67
  };
67
68
  }
68
69
  if (opportunity.action === types_1.OpportunityAction.BORROW && opportunity.explorerAddress) {
69
- const borrowAToken = (_b = opportunity.explorerAddress) === null || _b === void 0 ? void 0 : _b.toLowerCase();
70
+ const borrowAToken = (_e = opportunity.explorerAddress) === null || _e === void 0 ? void 0 : _e.toLowerCase();
70
71
  if (!acc[borrowAToken])
71
72
  acc[borrowAToken] = {};
72
73
  acc[borrowAToken].borrow = {
@@ -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', {
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,6 +1,7 @@
1
1
  import { Client } from 'viem';
2
2
  import { CompoundMarketData, CompoundV3AssetsData, CompoundV3MarketsData, CompoundV3PositionData } from '../types';
3
3
  import { Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances } from '../types/common';
4
+ export { getCompoundV3MerklOpportunities, attachCompoundV3MerklIncentives } from './merkl';
4
5
  export declare const _getCompoundV3MarketsData: (provider: Client, network: NetworkNumber, selectedMarket: CompoundMarketData, defaultProvider: Client) => Promise<CompoundV3MarketsData>;
5
6
  export declare const getCompoundV3MarketsData: (provider: EthereumProvider, network: NetworkNumber, selectedMarket: CompoundMarketData, defaultProvider: EthereumProvider) => Promise<CompoundV3MarketsData>;
6
7
  export declare const EMPTY_COMPOUND_V3_DATA: {
@@ -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.getCompoundV3FullPositionData = exports.getCompoundV3AccountData = exports._getCompoundV3AccountData = exports.getCompoundV3AccountBalances = exports._getCompoundV3AccountBalances = exports.EMPTY_USED_ASSET = exports.EMPTY_COMPOUND_V3_DATA = exports.getCompoundV3MarketsData = exports._getCompoundV3MarketsData = void 0;
15
+ exports.getCompoundV3FullPositionData = exports.getCompoundV3AccountData = exports._getCompoundV3AccountData = exports.getCompoundV3AccountBalances = exports._getCompoundV3AccountBalances = exports.EMPTY_USED_ASSET = exports.EMPTY_COMPOUND_V3_DATA = exports.getCompoundV3MarketsData = exports._getCompoundV3MarketsData = exports.attachCompoundV3MerklIncentives = exports.getCompoundV3MerklOpportunities = void 0;
16
16
  const decimal_js_1 = __importDefault(require("decimal.js"));
17
17
  const tokens_1 = require("@defisaver/tokens");
18
18
  const contracts_1 = require("../contracts");
@@ -25,6 +25,10 @@ const compoundHelpers_1 = require("../helpers/compoundHelpers");
25
25
  const compound_1 = require("../markets/compound");
26
26
  const priceService_1 = require("../services/priceService");
27
27
  const viem_1 = require("../services/viem");
28
+ const merkl_1 = require("./merkl");
29
+ var merkl_2 = require("./merkl");
30
+ Object.defineProperty(exports, "getCompoundV3MerklOpportunities", { enumerable: true, get: function () { return merkl_2.getCompoundV3MerklOpportunities; } });
31
+ Object.defineProperty(exports, "attachCompoundV3MerklIncentives", { enumerable: true, get: function () { return merkl_2.attachCompoundV3MerklIncentives; } });
28
32
  const getSupportedAssetsAddressesForMarket = (selectedMarket, network) => selectedMarket.collAssets.map(asset => (0, tokens_1.getAssetInfo)((0, utils_1.ethToWeth)(asset), network)).map(addr => addr.address.toLowerCase());
29
33
  const getBaseAssetPriceFunction = (asset) => {
30
34
  switch (asset) {
@@ -38,12 +42,13 @@ const getBaseAssetPriceFunction = (asset) => {
38
42
  };
39
43
  const _getCompoundV3MarketsData = (provider, network, selectedMarket, defaultProvider) => __awaiter(void 0, void 0, void 0, function* () {
40
44
  const contract = (0, contracts_1.CompV3ViewContractViem)(provider, network);
41
- const [baseAssetPrice, compPrice, baseTokenInfo, collInfos, govInfo] = yield Promise.all([
45
+ const [baseAssetPrice, compPrice, baseTokenInfo, collInfos, govInfo, merklOpportunities] = yield Promise.all([
42
46
  getBaseAssetPriceFunction(selectedMarket.baseAsset)(defaultProvider),
43
47
  (0, priceService_1.getCompPrice)(defaultProvider),
44
48
  contract.read.getFullBaseTokenInfo([selectedMarket.baseMarketAddress]),
45
49
  contract.read.getFullCollInfos([selectedMarket.baseMarketAddress]),
46
50
  contract.read.getGovernanceInfoFull([selectedMarket.baseMarketAddress]),
51
+ (0, merkl_1.getCompoundV3MerklOpportunities)(),
47
52
  ]);
48
53
  const { isSupplyPaused, isWithdrawPaused } = govInfo;
49
54
  const supportedAssetsAddresses = getSupportedAssetsAddressesForMarket(selectedMarket, network);
@@ -63,6 +68,7 @@ const _getCompoundV3MarketsData = (provider, network, selectedMarket, defaultPro
63
68
  const base = (0, compoundHelpers_1.formatBaseData)(baseTokenInfo, network, baseAssetPrice, isSupplyPaused, isWithdrawPaused);
64
69
  const payload = {};
65
70
  const baseObj = Object.assign(Object.assign({}, base), (yield (0, compoundHelpers_1.getIncentiveApys)(base, compPrice)));
71
+ (0, merkl_1.attachCompoundV3MerklIncentives)(baseObj, colls, selectedMarket.baseMarketAddress, network, merklOpportunities);
66
72
  const allAssets = [baseObj, ...colls];
67
73
  allAssets
68
74
  .sort((a, b) => {
@@ -0,0 +1,16 @@
1
+ import { CompoundV3AssetData, MerklOpportunity, NetworkNumber } from '../types';
2
+ /**
3
+ * Merkl tags Compound V3 reward campaigns with COMPOUND_V3_* opportunity types (e.g.
4
+ * COMPOUND_V3_BORROW_FROM_COLLATERAL) and identifies the comet via `explorerAddress`. Campaign
5
+ * identifiers are opaque hashes, passed through as `eligibilityId` so conditional campaigns —
6
+ * like borrow-from-collateral ones, whose reward is min(collateral * LTV, borrow amount) — can
7
+ * be gated and sized by a curated check in EligibilityMapping; unknown ids apply
8
+ * unconditionally, mirroring Aave V3.
9
+ */
10
+ export declare const getCompoundV3MerklOpportunities: () => Promise<MerklOpportunity[]>;
11
+ /**
12
+ * Appends the comet's Merkl campaigns to its assets' incentive arrays (mutating them, like the
13
+ * staking incentives are attached). BORROW campaigns land on the base asset — the only borrowable
14
+ * one — while LEND campaigns land on the asset the campaign's first token resolves to.
15
+ */
16
+ export declare const attachCompoundV3MerklIncentives: (baseAsset: CompoundV3AssetData, collAssets: CompoundV3AssetData[], baseMarketAddress: string, chainId: NetworkNumber, opportunities: MerklOpportunity[]) => void;
@@ -0,0 +1,77 @@
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.attachCompoundV3MerklIncentives = exports.getCompoundV3MerklOpportunities = void 0;
13
+ const tokens_1 = require("@defisaver/tokens");
14
+ const moneymarket_1 = require("../moneymarket");
15
+ const merkl_1 = require("../services/merkl");
16
+ const utils_1 = require("../services/utils");
17
+ const types_1 = require("../types");
18
+ /**
19
+ * Merkl tags Compound V3 reward campaigns with COMPOUND_V3_* opportunity types (e.g.
20
+ * COMPOUND_V3_BORROW_FROM_COLLATERAL) and identifies the comet via `explorerAddress`. Campaign
21
+ * identifiers are opaque hashes, passed through as `eligibilityId` so conditional campaigns —
22
+ * like borrow-from-collateral ones, whose reward is min(collateral * LTV, borrow amount) — can
23
+ * be gated and sized by a curated check in EligibilityMapping; unknown ids apply
24
+ * unconditionally, mirroring Aave V3.
25
+ */
26
+ const getCompoundV3MerklOpportunities = () => __awaiter(void 0, void 0, void 0, function* () {
27
+ try {
28
+ return yield (0, merkl_1.fetchAllMerklOpportunities)({
29
+ mainProtocolId: 'compound-v3',
30
+ status: types_1.OpportunityStatus.LIVE,
31
+ });
32
+ }
33
+ catch (e) {
34
+ console.error('Failed to fetch Compound V3 Merkl campaigns', e);
35
+ return [];
36
+ }
37
+ });
38
+ exports.getCompoundV3MerklOpportunities = getCompoundV3MerklOpportunities;
39
+ const buildMerklIncentive = (opportunity) => {
40
+ var _a, _b, _c, _d, _e, _f;
41
+ const token = ((_d = (_c = (_b = (_a = opportunity.rewardsRecord) === null || _a === void 0 ? void 0 : _a.breakdowns) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.token) === null || _d === void 0 ? void 0 : _d.symbol) || ((_f = (_e = opportunity.tokens) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.symbol) || '';
42
+ return {
43
+ apy: (0, moneymarket_1.aprToApy)(opportunity.apr),
44
+ token,
45
+ incentiveKind: types_1.IncentiveKind.Reward,
46
+ description: `Eligible for ${token} rewards through Merkl.${opportunity.description ? `\n${opportunity.description}` : ''}`,
47
+ eligibilityId: opportunity.identifier,
48
+ };
49
+ };
50
+ /**
51
+ * Appends the comet's Merkl campaigns to its assets' incentive arrays (mutating them, like the
52
+ * staking incentives are attached). BORROW campaigns land on the base asset — the only borrowable
53
+ * one — while LEND campaigns land on the asset the campaign's first token resolves to.
54
+ */
55
+ const attachCompoundV3MerklIncentives = (baseAsset, collAssets, baseMarketAddress, chainId, opportunities) => {
56
+ opportunities
57
+ .filter((o) => o.chainId === chainId
58
+ && o.status === types_1.OpportunityStatus.LIVE
59
+ && typeof o.type === 'string' && o.type.startsWith('COMPOUND_V3')
60
+ && o.explorerAddress && (0, utils_1.compareAddresses)(o.explorerAddress, baseMarketAddress))
61
+ .forEach((o) => {
62
+ var _a, _b;
63
+ const incentive = buildMerklIncentive(o);
64
+ if (o.action === types_1.OpportunityAction.BORROW) {
65
+ baseAsset.borrowIncentives.push(incentive);
66
+ }
67
+ else if (o.action === types_1.OpportunityAction.LEND) {
68
+ const campaignTokenAddress = (_b = (_a = o.tokens) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.address;
69
+ if (!campaignTokenAddress)
70
+ return;
71
+ const campaignSymbol = (0, utils_1.wethToEth)((0, tokens_1.getAssetInfoByAddress)(campaignTokenAddress, chainId).symbol);
72
+ const target = [baseAsset, ...collAssets].find((asset) => asset.symbol === campaignSymbol);
73
+ target === null || target === void 0 ? void 0 : target.supplyIncentives.push(incentive);
74
+ }
75
+ });
76
+ };
77
+ exports.attachCompoundV3MerklIncentives = attachCompoundV3MerklIncentives;
@@ -1,6 +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 { FluidMerklOpportunityType, buildFluidMerklRewardMap, getFluidMerklCampaigns, attachFluidMerklIncentives, } from './merkl';
4
5
  export declare const EMPTY_USED_ASSET: {
5
6
  isSupplied: boolean;
6
7
  isBorrowed: boolean;
@@ -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 = 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");
@@ -25,6 +25,12 @@ const constants_1 = require("../constants");
25
25
  const priceService_1 = require("../services/priceService");
26
26
  const staking_1 = require("../staking");
27
27
  const viem_1 = require("../services/viem");
28
+ const merkl_1 = require("./merkl");
29
+ var merkl_2 = require("./merkl");
30
+ Object.defineProperty(exports, "FluidMerklOpportunityType", { enumerable: true, get: function () { return merkl_2.FluidMerklOpportunityType; } });
31
+ Object.defineProperty(exports, "buildFluidMerklRewardMap", { enumerable: true, get: function () { return merkl_2.buildFluidMerklRewardMap; } });
32
+ Object.defineProperty(exports, "getFluidMerklCampaigns", { enumerable: true, get: function () { return merkl_2.getFluidMerklCampaigns; } });
33
+ Object.defineProperty(exports, "attachFluidMerklIncentives", { enumerable: true, get: function () { return merkl_2.attachFluidMerklIncentives; } });
28
34
  exports.EMPTY_USED_ASSET = {
29
35
  isSupplied: false,
30
36
  isBorrowed: false,
@@ -1106,8 +1112,12 @@ const parseUserData = (userPositionData, vaultData) => {
1106
1112
  };
1107
1113
  const _getFluidMarketData = (provider, network, market) => __awaiter(void 0, void 0, void 0, function* () {
1108
1114
  const view = (0, contracts_1.FluidViewContractViem)(provider, network);
1109
- const data = yield view.read.getVaultData([market.marketAddress]);
1110
- return parseMarketData(provider, data, network);
1115
+ const [data, merklCampaigns] = yield Promise.all([
1116
+ view.read.getVaultData([market.marketAddress]),
1117
+ (0, merkl_1.getFluidMerklCampaigns)(network),
1118
+ ]);
1119
+ const marketData = yield parseMarketData(provider, data, network);
1120
+ return marketData ? (0, merkl_1.attachFluidMerklIncentives)(marketData, merklCampaigns) : marketData;
1111
1121
  });
1112
1122
  exports._getFluidMarketData = _getFluidMarketData;
1113
1123
  const getFluidMarketData = (provider, network, market) => __awaiter(void 0, void 0, void 0, function* () { return (0, exports._getFluidMarketData)((0, viem_1.getViemProvider)(provider, network), network, market); });
@@ -1130,11 +1140,15 @@ const getFluidPosition = (provider, network, vaultId, extractedState) => __await
1130
1140
  exports.getFluidPosition = getFluidPosition;
1131
1141
  const _getFluidPositionWithMarket = (provider, network, vaultId) => __awaiter(void 0, void 0, void 0, function* () {
1132
1142
  const view = (0, contracts_1.FluidViewContractViem)(provider, network);
1133
- const data = yield view.read.getPositionByNftId([BigInt(vaultId)]);
1134
- const marketData = yield parseMarketData(provider, data[1], network);
1135
- if (!marketData) {
1143
+ const [data, merklCampaigns] = yield Promise.all([
1144
+ view.read.getPositionByNftId([BigInt(vaultId)]),
1145
+ (0, merkl_1.getFluidMerklCampaigns)(network),
1146
+ ]);
1147
+ const parsedMarketData = yield parseMarketData(provider, data[1], network);
1148
+ if (!parsedMarketData) {
1136
1149
  return;
1137
1150
  }
1151
+ const marketData = (0, merkl_1.attachFluidMerklIncentives)(parsedMarketData, merklCampaigns);
1138
1152
  const userData = parseUserData(data[0], marketData);
1139
1153
  return {
1140
1154
  userData,
@@ -1147,8 +1161,14 @@ exports.getFluidPositionWithMarket = getFluidPositionWithMarket;
1147
1161
  const _getAllFluidMarketDataChunked = (network, provider) => __awaiter(void 0, void 0, void 0, function* () {
1148
1162
  const versions = (0, markets_1.getFluidVersionsDataForNetwork)(network);
1149
1163
  const view = (0, contracts_1.FluidViewContractViem)(provider, network);
1150
- const data = yield Promise.all(versions.map((version) => view.read.getVaultData([version.marketAddress])));
1151
- return Promise.all(data.map((item, i) => __awaiter(void 0, void 0, void 0, function* () { return parseMarketData(provider, item, network); })));
1164
+ const [data, merklCampaigns] = yield Promise.all([
1165
+ Promise.all(versions.map((version) => view.read.getVaultData([version.marketAddress]))),
1166
+ (0, merkl_1.getFluidMerklCampaigns)(network),
1167
+ ]);
1168
+ return Promise.all(data.map((item) => __awaiter(void 0, void 0, void 0, function* () {
1169
+ const marketData = yield parseMarketData(provider, item, network);
1170
+ return marketData ? (0, merkl_1.attachFluidMerklIncentives)(marketData, merklCampaigns) : marketData;
1171
+ })));
1152
1172
  });
1153
1173
  exports._getAllFluidMarketDataChunked = _getAllFluidMarketDataChunked;
1154
1174
  const getAllFluidMarketDataChunked = (network, provider) => __awaiter(void 0, void 0, void 0, function* () { return (0, exports._getAllFluidMarketDataChunked)(network, (0, viem_1.getViemProvider)(provider, network, { batch: { multicall: true } })); });
@@ -0,0 +1,31 @@
1
+ import { FluidMarketData, FluidMerklRewardMap, MerklOpportunity, NetworkNumber } from '../types';
2
+ /**
3
+ * Merkl tags Fluid vault-scoped reward campaigns via the opportunity `type` field:
4
+ * - FLUIDVAULT_COLLATERAL → reward for supplying collateral to the vault
5
+ * - FLUIDVAULT_BORROW → reward for borrowing from the vault
6
+ * (ERC20LOGPROCESSOR campaigns target fToken earn positions rather than vaults, so they don't
7
+ * belong on vault market data.)
8
+ *
9
+ * A campaign identifies its vault via `identifier` — the vault address. Conditional campaigns
10
+ * append a marker to it (e.g. `0x5668…eeaBORROW_BL`, excluding holders who borrow the reward
11
+ * asset elsewhere); those are still attached, with the full identifier passed through as
12
+ * `eligibilityId` so a curated check in EligibilityMapping can gate them in net APY — unknown
13
+ * ids apply unconditionally, mirroring Aave V3. Whitelist-gated campaigns only accrue to
14
+ * whitelisted addresses, so they are skipped rather than advertised to every user.
15
+ */
16
+ export declare enum FluidMerklOpportunityType {
17
+ Collateral = "FLUIDVAULT_COLLATERAL",
18
+ Borrow = "FLUIDVAULT_BORROW"
19
+ }
20
+ export declare const buildFluidMerklRewardMap: (opportunities: MerklOpportunity[], chainId: NetworkNumber) => FluidMerklRewardMap;
21
+ /**
22
+ * Fetches live vault-scoped Fluid campaigns for the chain, keyed by vault address. Never throws —
23
+ * on any failure it returns an empty map, so Merkl being down can't break market data.
24
+ */
25
+ export declare const getFluidMerklCampaigns: (chainId: NetworkNumber) => Promise<FluidMerklRewardMap>;
26
+ /**
27
+ * Appends the vault's Merkl campaigns to its assets' incentive arrays — supply rewards on every
28
+ * suppliable asset and borrow rewards on every borrowable one. Smart collateral/debt vaults hold
29
+ * the position across both pair tokens, so the pro-rata reward APY applies to each side's value.
30
+ */
31
+ export declare const attachFluidMerklIncentives: (marketData: FluidMarketData, campaigns: FluidMerklRewardMap) => FluidMarketData;
@@ -0,0 +1,99 @@
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.attachFluidMerklIncentives = exports.getFluidMerklCampaigns = exports.buildFluidMerklRewardMap = exports.FluidMerklOpportunityType = void 0;
13
+ const moneymarket_1 = require("../moneymarket");
14
+ const merkl_1 = require("../services/merkl");
15
+ const types_1 = require("../types");
16
+ /**
17
+ * Merkl tags Fluid vault-scoped reward campaigns via the opportunity `type` field:
18
+ * - FLUIDVAULT_COLLATERAL → reward for supplying collateral to the vault
19
+ * - FLUIDVAULT_BORROW → reward for borrowing from the vault
20
+ * (ERC20LOGPROCESSOR campaigns target fToken earn positions rather than vaults, so they don't
21
+ * belong on vault market data.)
22
+ *
23
+ * A campaign identifies its vault via `identifier` — the vault address. Conditional campaigns
24
+ * append a marker to it (e.g. `0x5668…eeaBORROW_BL`, excluding holders who borrow the reward
25
+ * asset elsewhere); those are still attached, with the full identifier passed through as
26
+ * `eligibilityId` so a curated check in EligibilityMapping can gate them in net APY — unknown
27
+ * ids apply unconditionally, mirroring Aave V3. Whitelist-gated campaigns only accrue to
28
+ * whitelisted addresses, so they are skipped rather than advertised to every user.
29
+ */
30
+ var FluidMerklOpportunityType;
31
+ (function (FluidMerklOpportunityType) {
32
+ FluidMerklOpportunityType["Collateral"] = "FLUIDVAULT_COLLATERAL";
33
+ FluidMerklOpportunityType["Borrow"] = "FLUIDVAULT_BORROW";
34
+ })(FluidMerklOpportunityType || (exports.FluidMerklOpportunityType = FluidMerklOpportunityType = {}));
35
+ // '0x' + 20-byte vault address; conditional campaigns append a marker after it
36
+ const VAULT_ADDRESS_LENGTH = 42;
37
+ const buildMerklIncentive = (opportunity) => {
38
+ var _a, _b, _c, _d, _e, _f;
39
+ const token = ((_d = (_c = (_b = (_a = opportunity.rewardsRecord) === null || _a === void 0 ? void 0 : _a.breakdowns) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.token) === null || _d === void 0 ? void 0 : _d.symbol) || ((_f = (_e = opportunity.tokens) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.symbol) || '';
40
+ return {
41
+ apy: (0, moneymarket_1.aprToApy)(opportunity.apr),
42
+ token,
43
+ incentiveKind: types_1.IncentiveKind.Reward,
44
+ description: `Eligible for ${token} rewards through Merkl.${opportunity.description ? `\n${opportunity.description}` : ''}`,
45
+ eligibilityId: opportunity.identifier,
46
+ };
47
+ };
48
+ const buildFluidMerklRewardMap = (opportunities, chainId) => {
49
+ const result = {};
50
+ opportunities
51
+ .filter((o) => o.chainId === chainId)
52
+ .filter((o) => o.status === types_1.OpportunityStatus.LIVE)
53
+ .filter((o) => Object.values(FluidMerklOpportunityType).includes(o.type))
54
+ .filter((o) => { var _a; return !((_a = o.identifier) === null || _a === void 0 ? void 0 : _a.includes('WHITELIST')); })
55
+ .forEach((o) => {
56
+ var _a;
57
+ const vaultAddress = (_a = o.identifier) === null || _a === void 0 ? void 0 : _a.slice(0, VAULT_ADDRESS_LENGTH).toLowerCase();
58
+ if (!vaultAddress || vaultAddress.length !== VAULT_ADDRESS_LENGTH)
59
+ return;
60
+ if (!result[vaultAddress])
61
+ result[vaultAddress] = { supply: [], borrow: [] };
62
+ result[vaultAddress][o.type === FluidMerklOpportunityType.Borrow ? 'borrow' : 'supply'].push(buildMerklIncentive(o));
63
+ });
64
+ return result;
65
+ };
66
+ exports.buildFluidMerklRewardMap = buildFluidMerklRewardMap;
67
+ /**
68
+ * Fetches live vault-scoped Fluid campaigns for the chain, keyed by vault address. Never throws —
69
+ * on any failure it returns an empty map, so Merkl being down can't break market data.
70
+ */
71
+ const getFluidMerklCampaigns = (chainId) => __awaiter(void 0, void 0, void 0, function* () {
72
+ try {
73
+ const opportunities = yield (0, merkl_1.fetchAllMerklOpportunities)({
74
+ mainProtocolId: 'fluid',
75
+ type: Object.values(FluidMerklOpportunityType).join(','),
76
+ status: types_1.OpportunityStatus.LIVE,
77
+ });
78
+ return (0, exports.buildFluidMerklRewardMap)(opportunities, chainId);
79
+ }
80
+ catch (e) {
81
+ console.error('Failed to fetch Fluid Merkl campaigns', e);
82
+ return {};
83
+ }
84
+ });
85
+ exports.getFluidMerklCampaigns = getFluidMerklCampaigns;
86
+ /**
87
+ * Appends the vault's Merkl campaigns to its assets' incentive arrays — supply rewards on every
88
+ * suppliable asset and borrow rewards on every borrowable one. Smart collateral/debt vaults hold
89
+ * the position across both pair tokens, so the pro-rata reward APY applies to each side's value.
90
+ */
91
+ const attachFluidMerklIncentives = (marketData, campaigns) => {
92
+ var _a;
93
+ const vaultCampaigns = campaigns[(_a = marketData.marketData.marketAddress) === null || _a === void 0 ? void 0 : _a.toLowerCase()];
94
+ if (!vaultCampaigns || (!vaultCampaigns.supply.length && !vaultCampaigns.borrow.length))
95
+ return marketData;
96
+ const assetsData = Object.fromEntries(Object.entries(marketData.assetsData).map(([symbol, asset]) => [symbol, Object.assign(Object.assign({}, asset), { supplyIncentives: asset.canBeSupplied ? [...asset.supplyIncentives, ...vaultCampaigns.supply] : asset.supplyIncentives, borrowIncentives: asset.canBeBorrowed ? [...asset.borrowIncentives, ...vaultCampaigns.borrow] : asset.borrowIncentives })]));
97
+ return Object.assign(Object.assign({}, marketData), { assetsData });
98
+ };
99
+ exports.attachFluidMerklIncentives = attachFluidMerklIncentives;
@@ -1,6 +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 { MorphoBlueMerklOpportunityType, addMorphoBlueMerklOpportunitiesToMarketInfo, getMorphoBlueMerklOpportunities, addMorphoBlueMerklRewardsToMarketInfo, } from './merkl';
4
5
  export declare const addMorphoBlueRewardsToMarketInfo: (marketInfo: MorphoBlueMarketInfo, rewards: MorphoBlueMarketRewards) => MorphoBlueMarketInfo;
5
6
  export declare function _getMorphoBlueMarketData(provider: Client, network: NetworkNumber, selectedMarket: MorphoBlueMarketData): Promise<MorphoBlueMarketInfo>;
6
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 = 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;
@@ -31,6 +31,12 @@ const utils_1 = require("../services/utils");
31
31
  const morphoBlueHelpers_1 = require("../helpers/morphoBlueHelpers");
32
32
  const priceService_1 = require("../services/priceService");
33
33
  const viem_1 = require("../services/viem");
34
+ const merkl_1 = require("./merkl");
35
+ var merkl_2 = require("./merkl");
36
+ Object.defineProperty(exports, "MorphoBlueMerklOpportunityType", { enumerable: true, get: function () { return merkl_2.MorphoBlueMerklOpportunityType; } });
37
+ Object.defineProperty(exports, "addMorphoBlueMerklOpportunitiesToMarketInfo", { enumerable: true, get: function () { return merkl_2.addMorphoBlueMerklOpportunitiesToMarketInfo; } });
38
+ Object.defineProperty(exports, "getMorphoBlueMerklOpportunities", { enumerable: true, get: function () { return merkl_2.getMorphoBlueMerklOpportunities; } });
39
+ Object.defineProperty(exports, "addMorphoBlueMerklRewardsToMarketInfo", { enumerable: true, get: function () { return merkl_2.addMorphoBlueMerklRewardsToMarketInfo; } });
34
40
  const HARDCODED_USD_STABLE_PRICE = '100000000'; // $1 with 8 decimals
35
41
  const getMorphoRewardIncentives = (apy) => [{
36
42
  token: 'MORPHO',
@@ -134,15 +140,15 @@ function getMorphoBlueMarketDataInternal(provider, network, selectedMarket) {
134
140
  }
135
141
  function _getMorphoBlueMarketData(provider, network, selectedMarket) {
136
142
  return __awaiter(this, void 0, void 0, function* () {
137
- const marketInfo = yield getMorphoBlueMarketDataInternal(provider, network, selectedMarket);
138
- try {
139
- const rewards = yield (0, morphoBlueHelpers_1.getRewardsForMarket)(selectedMarket.marketId, network);
140
- return (0, exports.addMorphoBlueRewardsToMarketInfo)(marketInfo, rewards);
141
- }
142
- catch (error) {
143
- console.error(error);
144
- return (0, exports.addMorphoBlueRewardsToMarketInfo)(marketInfo, { supplyApy: '0', borrowApy: '0' });
145
- }
143
+ const [marketInfo, rewards, merklOpportunities] = yield Promise.all([
144
+ getMorphoBlueMarketDataInternal(provider, network, selectedMarket),
145
+ (0, morphoBlueHelpers_1.getRewardsForMarket)(selectedMarket.marketId, network).catch((error) => {
146
+ console.error(error);
147
+ return { supplyApy: '0', borrowApy: '0' };
148
+ }),
149
+ (0, merkl_1.getMorphoBlueMerklOpportunities)(),
150
+ ]);
151
+ return (0, merkl_1.addMorphoBlueMerklOpportunitiesToMarketInfo)((0, exports.addMorphoBlueRewardsToMarketInfo)(marketInfo, rewards), selectedMarket, network, merklOpportunities);
146
152
  });
147
153
  }
148
154
  function _getMorphoBluePortfolioMarketData(provider, network, selectedMarket) {
@@ -0,0 +1,35 @@
1
+ import { MerklOpportunity, MorphoBlueMarketData, MorphoBlueMarketInfo, NetworkNumber } from '../types';
2
+ /**
3
+ * Merkl tags Morpho Blue market-level reward campaigns via the opportunity `type` field:
4
+ * - MORPHOSUPPLY → reward for supplying the market's loan asset
5
+ * - MORPHOCOLLATERAL → reward for depositing the market's collateral asset
6
+ * - MORPHOBORROW → reward for borrowing the market's loan asset
7
+ * (MORPHOVAULT/ERC20LOGPROCESSOR are MetaMorpho vault campaigns and MORPHOSUPPLY_SINGLETOKEN is
8
+ * token-wide rather than market-scoped, so none of them belong on per-market data.)
9
+ *
10
+ * A campaign identifies its market via `identifier` — the first 20 bytes of the 32-byte Morpho
11
+ * market id, formatted as a checksummed address. Whitelist-gated campaigns append a marker to that
12
+ * identifier (e.g. `0x54cf…c46WHITELIST_CAMPAIGN`); their rewards only accrue to whitelisted
13
+ * addresses, so they are skipped rather than advertised to every user.
14
+ */
15
+ export declare enum MorphoBlueMerklOpportunityType {
16
+ Supply = "MORPHOSUPPLY",
17
+ Collateral = "MORPHOCOLLATERAL",
18
+ Borrow = "MORPHOBORROW"
19
+ }
20
+ /**
21
+ * Appends the given live Merkl campaigns for the market to its `assetsData` incentive arrays
22
+ * (collateral supply / loan supply / loan borrow). Existing Merkl incentives are replaced rather
23
+ * than duplicated, so re-applying on refreshed data is safe.
24
+ */
25
+ export declare const addMorphoBlueMerklOpportunitiesToMarketInfo: (marketInfo: MorphoBlueMarketInfo, selectedMarket: MorphoBlueMarketData, chainId: NetworkNumber, opportunities: MerklOpportunity[]) => MorphoBlueMarketInfo;
26
+ /**
27
+ * Fetches live market-scoped Morpho Blue campaigns for all chains. Never throws — on any failure
28
+ * it returns an empty list, so Merkl being down can't break market data.
29
+ */
30
+ export declare const getMorphoBlueMerklOpportunities: () => Promise<MerklOpportunity[]>;
31
+ /**
32
+ * Fetches live Merkl campaigns and appends the ones for the market to its `assetsData` incentive
33
+ * arrays. Never throws — on any failure the market info is returned unchanged.
34
+ */
35
+ export declare const addMorphoBlueMerklRewardsToMarketInfo: (marketInfo: MorphoBlueMarketInfo, selectedMarket: MorphoBlueMarketData, network: NetworkNumber) => Promise<MorphoBlueMarketInfo>;