@defisaver/positions-sdk 2.1.169-custom-fetching-dev → 2.1.169-custom-fetching-3-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/cjs/aaveV2/index.d.ts +4 -4
  2. package/cjs/aaveV2/index.js +7 -7
  3. package/cjs/aaveV3/index.d.ts +4 -3
  4. package/cjs/aaveV3/index.js +14 -10
  5. package/cjs/aaveV3/merkl.d.ts +5 -1
  6. package/cjs/aaveV3/merkl.js +8 -3
  7. package/cjs/aaveV4/index.d.ts +4 -3
  8. package/cjs/aaveV4/index.js +19 -16
  9. package/cjs/aaveV4/merkl.d.ts +10 -2
  10. package/cjs/aaveV4/merkl.js +15 -6
  11. package/cjs/claiming/aaveV3.d.ts +2 -2
  12. package/cjs/claiming/aaveV3.js +5 -4
  13. package/cjs/claiming/king.d.ts +2 -2
  14. package/cjs/claiming/king.js +3 -2
  15. package/cjs/claiming/spark.d.ts +3 -3
  16. package/cjs/claiming/spark.js +8 -7
  17. package/cjs/claiming/uniswap.d.ts +2 -2
  18. package/cjs/claiming/uniswap.js +3 -2
  19. package/cjs/compoundV2/index.d.ts +4 -4
  20. package/cjs/compoundV2/index.js +9 -9
  21. package/cjs/compoundV3/index.d.ts +5 -4
  22. package/cjs/compoundV3/index.js +17 -13
  23. package/cjs/compoundV3/merkl.d.ts +1 -1
  24. package/cjs/compoundV3/merkl.js +2 -5
  25. package/cjs/curveUsd/index.d.ts +5 -5
  26. package/cjs/curveUsd/index.js +17 -17
  27. package/cjs/fluid/index.d.ts +23 -22
  28. package/cjs/fluid/index.js +75 -72
  29. package/cjs/fluid/merkl.d.ts +5 -3
  30. package/cjs/fluid/merkl.js +11 -6
  31. package/cjs/liquity/index.d.ts +4 -4
  32. package/cjs/liquity/index.js +23 -23
  33. package/cjs/liquityV2/index.d.ts +10 -10
  34. package/cjs/liquityV2/index.js +59 -59
  35. package/cjs/llamaLend/index.d.ts +5 -5
  36. package/cjs/llamaLend/index.js +13 -13
  37. package/cjs/maker/index.d.ts +6 -6
  38. package/cjs/maker/index.js +16 -16
  39. package/cjs/morphoBlue/index.d.ts +7 -7
  40. package/cjs/morphoBlue/index.js +28 -26
  41. package/cjs/morphoBlue/merkl.d.ts +5 -3
  42. package/cjs/morphoBlue/merkl.js +6 -8
  43. package/cjs/morphoMidnight/index.d.ts +5 -5
  44. package/cjs/morphoMidnight/index.js +18 -18
  45. package/cjs/portfolio/customDeFiData.js +45 -40
  46. package/cjs/services/merkl.d.ts +36 -2
  47. package/cjs/services/merkl.js +142 -19
  48. package/cjs/services/priceService.d.ts +12 -12
  49. package/cjs/services/priceService.js +30 -29
  50. package/cjs/services/viem.d.ts +10 -2
  51. package/cjs/services/viem.js +27 -1
  52. package/cjs/spark/index.d.ts +4 -4
  53. package/cjs/spark/index.js +9 -9
  54. package/cjs/types/merkl.d.ts +18 -0
  55. package/cjs/types/portfolio.d.ts +2 -0
  56. package/cjs/umbrella/index.d.ts +2 -2
  57. package/cjs/umbrella/index.js +5 -4
  58. package/esm/aaveV2/index.d.ts +4 -4
  59. package/esm/aaveV2/index.js +8 -8
  60. package/esm/aaveV3/index.d.ts +4 -3
  61. package/esm/aaveV3/index.js +15 -11
  62. package/esm/aaveV3/merkl.d.ts +5 -1
  63. package/esm/aaveV3/merkl.js +9 -4
  64. package/esm/aaveV4/index.d.ts +4 -3
  65. package/esm/aaveV4/index.js +20 -17
  66. package/esm/aaveV4/merkl.d.ts +10 -2
  67. package/esm/aaveV4/merkl.js +16 -7
  68. package/esm/claiming/aaveV3.d.ts +2 -2
  69. package/esm/claiming/aaveV3.js +5 -4
  70. package/esm/claiming/king.d.ts +2 -2
  71. package/esm/claiming/king.js +3 -2
  72. package/esm/claiming/spark.d.ts +3 -3
  73. package/esm/claiming/spark.js +8 -7
  74. package/esm/claiming/uniswap.d.ts +2 -2
  75. package/esm/claiming/uniswap.js +3 -2
  76. package/esm/compoundV2/index.d.ts +4 -4
  77. package/esm/compoundV2/index.js +9 -9
  78. package/esm/compoundV3/index.d.ts +5 -4
  79. package/esm/compoundV3/index.js +19 -15
  80. package/esm/compoundV3/merkl.d.ts +1 -1
  81. package/esm/compoundV3/merkl.js +3 -6
  82. package/esm/curveUsd/index.d.ts +5 -5
  83. package/esm/curveUsd/index.js +17 -17
  84. package/esm/fluid/index.d.ts +23 -22
  85. package/esm/fluid/index.js +76 -73
  86. package/esm/fluid/merkl.d.ts +5 -3
  87. package/esm/fluid/merkl.js +12 -7
  88. package/esm/liquity/index.d.ts +4 -4
  89. package/esm/liquity/index.js +23 -23
  90. package/esm/liquityV2/index.d.ts +10 -10
  91. package/esm/liquityV2/index.js +60 -60
  92. package/esm/llamaLend/index.d.ts +5 -5
  93. package/esm/llamaLend/index.js +13 -13
  94. package/esm/maker/index.d.ts +6 -6
  95. package/esm/maker/index.js +16 -16
  96. package/esm/morphoBlue/index.d.ts +7 -7
  97. package/esm/morphoBlue/index.js +29 -27
  98. package/esm/morphoBlue/merkl.d.ts +5 -3
  99. package/esm/morphoBlue/merkl.js +7 -9
  100. package/esm/morphoMidnight/index.d.ts +5 -5
  101. package/esm/morphoMidnight/index.js +18 -18
  102. package/esm/portfolio/customDeFiData.js +47 -42
  103. package/esm/services/merkl.d.ts +36 -2
  104. package/esm/services/merkl.js +136 -18
  105. package/esm/services/priceService.d.ts +12 -12
  106. package/esm/services/priceService.js +31 -30
  107. package/esm/services/viem.d.ts +10 -2
  108. package/esm/services/viem.js +25 -0
  109. package/esm/spark/index.d.ts +4 -4
  110. package/esm/spark/index.js +10 -10
  111. package/esm/types/merkl.d.ts +18 -0
  112. package/esm/types/portfolio.d.ts +2 -0
  113. package/esm/umbrella/index.d.ts +2 -2
  114. package/esm/umbrella/index.js +5 -4
  115. package/package.json +1 -1
  116. package/src/aaveV2/index.ts +7 -7
  117. package/src/aaveV3/index.ts +15 -11
  118. package/src/aaveV3/merkl.ts +9 -4
  119. package/src/aaveV4/index.ts +19 -16
  120. package/src/aaveV4/merkl.ts +16 -7
  121. package/src/claiming/aaveV3.ts +5 -3
  122. package/src/claiming/king.ts +6 -3
  123. package/src/claiming/spark.ts +9 -6
  124. package/src/claiming/uniswap.ts +4 -3
  125. package/src/compoundV2/index.ts +10 -9
  126. package/src/compoundV3/index.ts +20 -14
  127. package/src/compoundV3/merkl.ts +5 -4
  128. package/src/curveUsd/index.ts +19 -17
  129. package/src/fluid/index.ts +88 -70
  130. package/src/fluid/merkl.ts +12 -7
  131. package/src/liquity/index.ts +23 -23
  132. package/src/liquityV2/index.ts +64 -56
  133. package/src/llamaLend/index.ts +15 -13
  134. package/src/maker/index.ts +19 -16
  135. package/src/morphoBlue/index.ts +23 -20
  136. package/src/morphoBlue/merkl.ts +9 -6
  137. package/src/morphoMidnight/index.ts +13 -13
  138. package/src/portfolio/customDeFiData.ts +48 -41
  139. package/src/services/merkl.ts +152 -19
  140. package/src/services/priceService.ts +33 -30
  141. package/src/services/viem.ts +16 -0
  142. package/src/spark/index.ts +11 -8
  143. package/src/types/merkl.ts +20 -0
  144. package/src/types/portfolio.ts +2 -0
  145. package/src/umbrella/index.ts +6 -5
@@ -16,7 +16,7 @@ import { calculateNetApy, getStakingApy, STAKING_ASSETS } from '../staking';
16
16
  import { isMainnetNetwork, wethToEth } from '../services/utils';
17
17
  import { getBorrowRate, getMorphoBlueAggregatedPositionData, getRewardsForMarket, getSupplyRate, } from '../helpers/morphoBlueHelpers';
18
18
  import { getChainlinkAssetAddress } from '../services/priceService';
19
- import { getViemProvider, setViemBlockNumber } from '../services/viem';
19
+ import { getBlockTimestamp, getViemProvider, setViemBlockNumber } from '../services/viem';
20
20
  import { addMorphoBlueMerklOpportunitiesToMarketInfo, getMorphoBlueMerklOpportunities } from './merkl';
21
21
  export { MorphoBlueMerklOpportunityType, addMorphoBlueMerklOpportunitiesToMarketInfo, getMorphoBlueMerklOpportunities, addMorphoBlueMerklRewardsToMarketInfo, } from './merkl';
22
22
  const HARDCODED_USD_STABLE_PRICE = '100000000'; // $1 with 8 decimals
@@ -33,8 +33,8 @@ export const addMorphoBlueRewardsToMarketInfo = (marketInfo, rewards) => (Object
33
33
  ...marketInfo.assetsData[marketInfo.loanToken].borrowIncentives.filter(({ token }) => token !== 'MORPHO'),
34
34
  ...getMorphoRewardIncentives(rewards.borrowApy),
35
35
  ] }) }) }));
36
- function getMorphoBlueMarketDataInternal(provider, network, selectedMarket) {
37
- return __awaiter(this, void 0, void 0, function* () {
36
+ function getMorphoBlueMarketDataInternal(provider_1, network_1, selectedMarket_1) {
37
+ return __awaiter(this, arguments, void 0, function* (provider, network, selectedMarket, blockNumber = 'latest') {
38
38
  const { loanToken, collateralToken, oracle, irm, lltv, oracleType, } = selectedMarket;
39
39
  const lltvInWei = new Dec(lltv).mul(WAD).toString();
40
40
  const loanTokenInfo = getAssetInfoByAddress(loanToken, network);
@@ -48,8 +48,8 @@ function getMorphoBlueMarketDataInternal(provider, network, selectedMarket) {
48
48
  if (isMainnet) {
49
49
  const feedRegistryContract = FeedRegistryContractViem(provider, NetworkNumber.Eth);
50
50
  const [_loanTokenPrice, _marketInfo] = yield Promise.all([
51
- isHardcodedUsdStable ? Promise.resolve(HARDCODED_USD_STABLE_PRICE) : feedRegistryContract.read.latestAnswer([loanTokenFeedAddress, USD_QUOTE]),
52
- morphoBlueViewContract.read.getMarketInfoNotTuple([loanToken, collateralToken, oracle, irm, BigInt(lltvInWei)]),
51
+ isHardcodedUsdStable ? Promise.resolve(HARDCODED_USD_STABLE_PRICE) : feedRegistryContract.read.latestAnswer([loanTokenFeedAddress, USD_QUOTE], setViemBlockNumber(blockNumber)),
52
+ morphoBlueViewContract.read.getMarketInfoNotTuple([loanToken, collateralToken, oracle, irm, BigInt(lltvInWei)], setViemBlockNumber(blockNumber)),
53
53
  ]);
54
54
  marketInfo = _marketInfo;
55
55
  loanTokenPrice = _loanTokenPrice;
@@ -59,8 +59,8 @@ function getMorphoBlueMarketDataInternal(provider, network, selectedMarket) {
59
59
  const feedRegistryContract = DFSFeedRegistryContractViem(provider, network);
60
60
  const [loanTokenPriceRound, _marketInfo] = yield Promise.all([
61
61
  isHardcodedUsdStable ? Promise.resolve([0, HARDCODED_USD_STABLE_PRICE]) // Normalize to match the expected object structure
62
- : feedRegistryContract.read.latestRoundData([loanTokenFeedAddress, USD_QUOTE]),
63
- morphoBlueViewContract.read.getMarketInfoNotTuple([loanToken, collateralToken, oracle, irm, BigInt(lltvInWei)]),
62
+ : feedRegistryContract.read.latestRoundData([loanTokenFeedAddress, USD_QUOTE], setViemBlockNumber(blockNumber)),
63
+ morphoBlueViewContract.read.getMarketInfoNotTuple([loanToken, collateralToken, oracle, irm, BigInt(lltvInWei)], setViemBlockNumber(blockNumber)),
64
64
  ]);
65
65
  marketInfo = _marketInfo;
66
66
  loanTokenPrice = loanTokenPriceRound[1].toString();
@@ -119,29 +119,31 @@ function getMorphoBlueMarketDataInternal(provider, network, selectedMarket) {
119
119
  };
120
120
  });
121
121
  }
122
- export function _getMorphoBlueMarketData(provider, network, selectedMarket) {
123
- return __awaiter(this, void 0, void 0, function* () {
122
+ export function _getMorphoBlueMarketData(provider_1, network_1, selectedMarket_1) {
123
+ return __awaiter(this, arguments, void 0, function* (provider, network, selectedMarket, blockNumber = 'latest') {
124
124
  const [marketInfo, rewards, merklOpportunities] = yield Promise.all([
125
- getMorphoBlueMarketDataInternal(provider, network, selectedMarket),
125
+ getMorphoBlueMarketDataInternal(provider, network, selectedMarket, blockNumber),
126
126
  getRewardsForMarket(selectedMarket.marketId, network).catch((error) => {
127
127
  console.error(error);
128
128
  return { supplyApy: '0', borrowApy: '0' };
129
129
  }),
130
- getMorphoBlueMerklOpportunities(),
130
+ // Merkl rewards are keyed by time: a historical block resolves to its timestamp first (one RPC
131
+ // call, none for 'latest') so the rewards in force at that moment are attached.
132
+ getBlockTimestamp(provider, blockNumber).then((asOfTimestamp) => getMorphoBlueMerklOpportunities(asOfTimestamp, network)),
131
133
  ]);
132
134
  return addMorphoBlueMerklOpportunitiesToMarketInfo(addMorphoBlueRewardsToMarketInfo(marketInfo, rewards), selectedMarket, network, merklOpportunities);
133
135
  });
134
136
  }
135
- export function _getMorphoBluePortfolioMarketData(provider, network, selectedMarket) {
136
- return getMorphoBlueMarketDataInternal(provider, network, selectedMarket);
137
+ export function _getMorphoBluePortfolioMarketData(provider, network, selectedMarket, blockNumber = 'latest') {
138
+ return getMorphoBlueMarketDataInternal(provider, network, selectedMarket, blockNumber);
137
139
  }
138
- export function getMorphoBlueMarketData(provider, network, selectedMarket) {
139
- return __awaiter(this, void 0, void 0, function* () {
140
- return _getMorphoBlueMarketData(getViemProvider(provider, network), network, selectedMarket);
140
+ export function getMorphoBlueMarketData(provider_1, network_1, selectedMarket_1) {
141
+ return __awaiter(this, arguments, void 0, function* (provider, network, selectedMarket, blockNumber = 'latest') {
142
+ return _getMorphoBlueMarketData(getViemProvider(provider, network), network, selectedMarket, blockNumber);
141
143
  });
142
144
  }
143
- export function getMorphoBluePortfolioMarketData(provider, network, selectedMarket) {
144
- return _getMorphoBluePortfolioMarketData(getViemProvider(provider, network), network, selectedMarket);
145
+ export function getMorphoBluePortfolioMarketData(provider, network, selectedMarket, blockNumber = 'latest') {
146
+ return _getMorphoBluePortfolioMarketData(getViemProvider(provider, network), network, selectedMarket, blockNumber);
145
147
  }
146
148
  export const getMorphoBluePositionDataWithMarketInfo = (data, marketInfo) => (Object.assign(Object.assign({}, data), getMorphoBlueAggregatedPositionData({
147
149
  usedAssets: data.usedAssets,
@@ -195,8 +197,8 @@ export const _getMorphoBlueAccountBalances = (provider, network, block, addressM
195
197
  return balances;
196
198
  });
197
199
  export const getMorphoBlueAccountBalances = (provider, network, block, addressMapping, address, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () { return _getMorphoBlueAccountBalances(getViemProvider(provider, network), network, block, addressMapping, address, selectedMarket); });
198
- export function _getMorphoBlueAccountData(provider, network, account, selectedMarket, marketInfo) {
199
- return __awaiter(this, void 0, void 0, function* () {
200
+ export function _getMorphoBlueAccountData(provider_1, network_1, account_1, selectedMarket_1, marketInfo_1) {
201
+ return __awaiter(this, arguments, void 0, function* (provider, network, account, selectedMarket, marketInfo, blockNumber = 'latest') {
200
202
  const { loanToken, collateralToken, oracle, irm, lltv, } = selectedMarket;
201
203
  const lltvInWei = new Dec(lltv).mul(WAD).toString();
202
204
  const viewContract = MorphoBlueViewContractViem(provider, network);
@@ -205,7 +207,7 @@ export function _getMorphoBlueAccountData(provider, network, account, selectedMa
205
207
  loanToken, collateralToken, oracle, irm, lltv: BigInt(lltvInWei),
206
208
  },
207
209
  account
208
- ]));
210
+ ], setViemBlockNumber(blockNumber)));
209
211
  const usedAssets = {};
210
212
  const loanTokenInfo = marketInfo.assetsData[marketInfo.loanToken];
211
213
  const loanTokenSupplied = assetAmountInEth(loanInfo.suppliedInAssets.toString(), marketInfo.loanToken);
@@ -235,13 +237,13 @@ export function _getMorphoBlueAccountData(provider, network, account, selectedMa
235
237
  return Object.assign({ supplyShares: loanInfo.supplyShares.toString(), borrowShares: loanInfo.borrowShares.toString(), usedAssets }, getMorphoBlueAggregatedPositionData({ usedAssets, assetsData: marketInfo.assetsData, marketInfo }));
236
238
  });
237
239
  }
238
- export function getMorphoBlueAccountData(provider, network, account, selectedMarket, marketInfo) {
239
- return __awaiter(this, void 0, void 0, function* () {
240
- return _getMorphoBlueAccountData(getViemProvider(provider, network), network, account, selectedMarket, marketInfo);
240
+ export function getMorphoBlueAccountData(provider_1, network_1, account_1, selectedMarket_1, marketInfo_1) {
241
+ return __awaiter(this, arguments, void 0, function* (provider, network, account, selectedMarket, marketInfo, blockNumber = 'latest') {
242
+ return _getMorphoBlueAccountData(getViemProvider(provider, network), network, account, selectedMarket, marketInfo, blockNumber);
241
243
  });
242
244
  }
243
- export function getMorphoEarn(provider, network, account, selectedMarket, marketInfo) {
244
- return __awaiter(this, void 0, void 0, function* () {
245
+ export function getMorphoEarn(provider_1, network_1, account_1, selectedMarket_1, marketInfo_1) {
246
+ return __awaiter(this, arguments, void 0, function* (provider, network, account, selectedMarket, marketInfo, blockNumber = 'latest') {
245
247
  const { loanToken, collateralToken, oracle, irm, lltv, } = selectedMarket;
246
248
  const lltvInWei = new Dec(lltv).mul(WAD).toString();
247
249
  const viewContract = MorphoBlueViewContractViem(provider, network);
@@ -250,7 +252,7 @@ export function getMorphoEarn(provider, network, account, selectedMarket, market
250
252
  loanToken, collateralToken, oracle, irm, lltv: BigInt(lltvInWei),
251
253
  },
252
254
  account
253
- ]));
255
+ ], setViemBlockNumber(blockNumber)));
254
256
  const loanTokenInfo = marketInfo.assetsData[marketInfo.loanToken];
255
257
  const loanTokenSupplied = assetAmountInEth(loanInfo.suppliedInAssets.toString(), marketInfo.loanToken);
256
258
  const loanTokenSuppliedUsd = new Dec(loanTokenSupplied).mul(loanTokenInfo.price).toString();
@@ -24,10 +24,12 @@ export declare enum MorphoBlueMerklOpportunityType {
24
24
  */
25
25
  export declare const addMorphoBlueMerklOpportunitiesToMarketInfo: (marketInfo: MorphoBlueMarketInfo, selectedMarket: MorphoBlueMarketData, chainId: NetworkNumber, opportunities: MerklOpportunity[]) => MorphoBlueMarketInfo;
26
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.
27
+ * Fetches live market-scoped Morpho Blue campaigns for all chains (or one, when `chainId` is given).
28
+ * With `asOfTimestamp` (unix seconds) the campaigns and APRs are the ones Merkl had at that moment
29
+ * instead. Never throws — on any failure it returns an empty list, so Merkl being down can't break
30
+ * market data.
29
31
  */
30
- export declare const getMorphoBlueMerklOpportunities: () => Promise<MerklOpportunity[]>;
32
+ export declare const getMorphoBlueMerklOpportunities: (asOfTimestamp?: number, chainId?: NetworkNumber) => Promise<MerklOpportunity[]>;
31
33
  /**
32
34
  * Fetches live Merkl campaigns and appends the ones for the market to its `assetsData` incentive
33
35
  * arrays. Never throws — on any failure the market info is returned unchanged.
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { aprToApy } from '../moneymarket';
11
- import { fetchAllMerklOpportunities } from '../services/merkl';
11
+ import { fetchMerklOpportunities } from '../services/merkl';
12
12
  import { IncentiveKind, OpportunityStatus, } from '../types';
13
13
  /**
14
14
  * Merkl tags Morpho Blue market-level reward campaigns via the opportunity `type` field:
@@ -73,16 +73,14 @@ export const addMorphoBlueMerklOpportunitiesToMarketInfo = (marketInfo, selected
73
73
  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] }) }) });
74
74
  };
75
75
  /**
76
- * Fetches live market-scoped Morpho Blue campaigns for all chains. Never throws — on any failure
77
- * it returns an empty list, so Merkl being down can't break market data.
76
+ * Fetches live market-scoped Morpho Blue campaigns for all chains (or one, when `chainId` is given).
77
+ * With `asOfTimestamp` (unix seconds) the campaigns and APRs are the ones Merkl had at that moment
78
+ * instead. Never throws — on any failure it returns an empty list, so Merkl being down can't break
79
+ * market data.
78
80
  */
79
- export const getMorphoBlueMerklOpportunities = () => __awaiter(void 0, void 0, void 0, function* () {
81
+ export const getMorphoBlueMerklOpportunities = (asOfTimestamp, chainId) => __awaiter(void 0, void 0, void 0, function* () {
80
82
  try {
81
- return yield fetchAllMerklOpportunities({
82
- mainProtocolId: 'morpho',
83
- type: Object.values(MorphoBlueMerklOpportunityType).join(','),
84
- status: OpportunityStatus.LIVE,
85
- });
83
+ return yield fetchMerklOpportunities(Object.assign({ mainProtocolId: 'morpho', type: Object.values(MorphoBlueMerklOpportunityType).join(','), status: OpportunityStatus.LIVE }, (chainId ? { chainId: chainId.toString() } : {})), asOfTimestamp);
86
84
  }
87
85
  catch (e) {
88
86
  console.error('Failed to fetch Morpho Blue Merkl campaigns', e);
@@ -1,13 +1,13 @@
1
1
  import { Client } from 'viem';
2
2
  import { Blockish, EthAddress, EthereumProvider, NetworkNumber, PositionBalances } from '../types/common';
3
3
  import { MorphoMidnightMarketData, MorphoMidnightMarketInfo, MorphoMidnightPositionData } from '../types';
4
- export declare function _getMorphoMidnightMarketData(provider: Client, network: NetworkNumber, selectedMarket: MorphoMidnightMarketData): Promise<MorphoMidnightMarketInfo>;
5
- export declare function getMorphoMidnightMarketData(provider: EthereumProvider, network: NetworkNumber, selectedMarket: MorphoMidnightMarketData): Promise<MorphoMidnightMarketInfo>;
6
- export declare function _getMorphoMidnightAccountData(provider: Client, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo): Promise<MorphoMidnightPositionData>;
7
- export declare function getMorphoMidnightAccountData(provider: EthereumProvider, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo): Promise<MorphoMidnightPositionData>;
4
+ export declare function _getMorphoMidnightMarketData(provider: Client, network: NetworkNumber, selectedMarket: MorphoMidnightMarketData, blockNumber?: Blockish): Promise<MorphoMidnightMarketInfo>;
5
+ export declare function getMorphoMidnightMarketData(provider: EthereumProvider, network: NetworkNumber, selectedMarket: MorphoMidnightMarketData, blockNumber?: Blockish): Promise<MorphoMidnightMarketInfo>;
6
+ export declare function _getMorphoMidnightAccountData(provider: Client, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo, blockNumber?: Blockish): Promise<MorphoMidnightPositionData>;
7
+ export declare function getMorphoMidnightAccountData(provider: EthereumProvider, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo, blockNumber?: Blockish): Promise<MorphoMidnightPositionData>;
8
8
  export declare const _getMorphoMidnightAccountBalances: (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, selectedMarket: MorphoMidnightMarketData, includeCredit?: boolean) => Promise<PositionBalances>;
9
9
  export declare const getMorphoMidnightAccountBalances: (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress, selectedMarket: MorphoMidnightMarketData) => Promise<PositionBalances>;
10
- export declare function getMorphoMidnightEarn(provider: Client, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo): Promise<{
10
+ export declare function getMorphoMidnightEarn(provider: Client, network: NetworkNumber, account: EthAddress, selectedMarket: MorphoMidnightMarketData, marketInfo: MorphoMidnightMarketInfo, blockNumber?: Blockish): Promise<{
11
11
  apy: string;
12
12
  amount: string;
13
13
  amountUsd: string;
@@ -20,8 +20,8 @@ import { getChainlinkAssetAddress } from '../services/priceService';
20
20
  import { getViemProvider, setViemBlockNumber } from '../services/viem';
21
21
  const HARDCODED_USD_STABLE_PRICE = '100000000'; // $1 with 8 decimals
22
22
  const nowInSeconds = () => Math.floor(Date.now() / 1000);
23
- export function _getMorphoMidnightMarketData(provider, network, selectedMarket) {
24
- return __awaiter(this, void 0, void 0, function* () {
23
+ export function _getMorphoMidnightMarketData(provider_1, network_1, selectedMarket_1) {
24
+ return __awaiter(this, arguments, void 0, function* (provider, network, selectedMarket, blockNumber = 'latest') {
25
25
  const { loanToken, collaterals, marketId } = selectedMarket;
26
26
  const loanTokenInfo = getAssetInfoByAddress(loanToken, network);
27
27
  const loanSym = wethToEth(loanTokenInfo.symbol);
@@ -33,8 +33,8 @@ export function _getMorphoMidnightMarketData(provider, network, selectedMarket)
33
33
  if (isMainnetNetwork(network)) {
34
34
  const feedRegistryContract = FeedRegistryContractViem(provider, NetworkNumber.Eth);
35
35
  const [_loanTokenPrice, _marketInfo] = yield Promise.all([
36
- isHardcodedUsdStable ? Promise.resolve(HARDCODED_USD_STABLE_PRICE) : feedRegistryContract.read.latestAnswer([loanTokenFeedAddress, USD_QUOTE]),
37
- viewContract.read.getMarketInfo([marketId]),
36
+ isHardcodedUsdStable ? Promise.resolve(HARDCODED_USD_STABLE_PRICE) : feedRegistryContract.read.latestAnswer([loanTokenFeedAddress, USD_QUOTE], setViemBlockNumber(blockNumber)),
37
+ viewContract.read.getMarketInfo([marketId], setViemBlockNumber(blockNumber)),
38
38
  ]);
39
39
  marketInfo = _marketInfo;
40
40
  loanTokenPrice = _loanTokenPrice;
@@ -43,8 +43,8 @@ export function _getMorphoMidnightMarketData(provider, network, selectedMarket)
43
43
  // Currently only Base is supported
44
44
  const feedRegistryContract = DFSFeedRegistryContractViem(provider, network);
45
45
  const [loanTokenPriceRound, _marketInfo] = yield Promise.all([
46
- isHardcodedUsdStable ? Promise.resolve([0, HARDCODED_USD_STABLE_PRICE]) : feedRegistryContract.read.latestRoundData([loanTokenFeedAddress, USD_QUOTE]),
47
- viewContract.read.getMarketInfo([marketId]),
46
+ isHardcodedUsdStable ? Promise.resolve([0, HARDCODED_USD_STABLE_PRICE]) : feedRegistryContract.read.latestRoundData([loanTokenFeedAddress, USD_QUOTE], setViemBlockNumber(blockNumber)),
47
+ viewContract.read.getMarketInfo([marketId], setViemBlockNumber(blockNumber)),
48
48
  ]);
49
49
  marketInfo = _marketInfo;
50
50
  loanTokenPrice = loanTokenPriceRound[1].toString();
@@ -114,16 +114,16 @@ export function _getMorphoMidnightMarketData(provider, network, selectedMarket)
114
114
  };
115
115
  });
116
116
  }
117
- export function getMorphoMidnightMarketData(provider, network, selectedMarket) {
118
- return __awaiter(this, void 0, void 0, function* () {
119
- return _getMorphoMidnightMarketData(getViemProvider(provider, network), network, selectedMarket);
117
+ export function getMorphoMidnightMarketData(provider_1, network_1, selectedMarket_1) {
118
+ return __awaiter(this, arguments, void 0, function* (provider, network, selectedMarket, blockNumber = 'latest') {
119
+ return _getMorphoMidnightMarketData(getViemProvider(provider, network), network, selectedMarket, blockNumber);
120
120
  });
121
121
  }
122
- export function _getMorphoMidnightAccountData(provider, network, account, selectedMarket, marketInfo) {
123
- return __awaiter(this, void 0, void 0, function* () {
122
+ export function _getMorphoMidnightAccountData(provider_1, network_1, account_1, selectedMarket_1, marketInfo_1) {
123
+ return __awaiter(this, arguments, void 0, function* (provider, network, account, selectedMarket, marketInfo, blockNumber = 'latest') {
124
124
  const { marketId, collaterals } = selectedMarket;
125
125
  const viewContract = MorphoMidnightViewContractViem(provider, network);
126
- const positionInfo = yield viewContract.read.getPositionInfo([marketId, account]);
126
+ const positionInfo = yield viewContract.read.getPositionInfo([marketId, account], setViemBlockNumber(blockNumber));
127
127
  const usedAssets = {};
128
128
  const loanTokenData = marketInfo.assetsData[marketInfo.loanToken];
129
129
  const credit = assetAmountInEth(positionInfo.credit.toString(), marketInfo.loanToken);
@@ -205,9 +205,9 @@ export function _getMorphoMidnightAccountData(provider, network, account, select
205
205
  borrowInfoStatus, maturity: marketInfo.maturity, isMatured: marketInfo.isMatured }, getMorphoMidnightAggregatedPositionData({ usedAssets, assetsData: assetsDataForApy, marketInfo }));
206
206
  });
207
207
  }
208
- export function getMorphoMidnightAccountData(provider, network, account, selectedMarket, marketInfo) {
209
- return __awaiter(this, void 0, void 0, function* () {
210
- return _getMorphoMidnightAccountData(getViemProvider(provider, network), network, account, selectedMarket, marketInfo);
208
+ export function getMorphoMidnightAccountData(provider_1, network_1, account_1, selectedMarket_1, marketInfo_1) {
209
+ return __awaiter(this, arguments, void 0, function* (provider, network, account, selectedMarket, marketInfo, blockNumber = 'latest') {
210
+ return _getMorphoMidnightAccountData(getViemProvider(provider, network), network, account, selectedMarket, marketInfo, blockNumber);
211
211
  });
212
212
  }
213
213
  export const _getMorphoMidnightAccountBalances = (provider_1, network_1, block_1, addressMapping_1, address_1, selectedMarket_1, ...args_1) => __awaiter(void 0, [provider_1, network_1, block_1, addressMapping_1, address_1, selectedMarket_1, ...args_1], void 0, function* (provider, network, block, addressMapping, address, selectedMarket, includeCredit = false) {
@@ -240,11 +240,11 @@ export const _getMorphoMidnightAccountBalances = (provider_1, network_1, block_1
240
240
  export const getMorphoMidnightAccountBalances = (provider, network, block, addressMapping, address, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () { return _getMorphoMidnightAccountBalances(getViemProvider(provider, network), network, block, addressMapping, address, selectedMarket); });
241
241
  // Lender-side (credit-only) supply position, mirroring getMorphoEarn. `amount` is the credit face value
242
242
  // redeemable at maturity; `apy` is '0' in MVP because the fixed yield is orderbook-derived, not on-chain.
243
- export function getMorphoMidnightEarn(provider, network, account, selectedMarket, marketInfo) {
244
- return __awaiter(this, void 0, void 0, function* () {
243
+ export function getMorphoMidnightEarn(provider_1, network_1, account_1, selectedMarket_1, marketInfo_1) {
244
+ return __awaiter(this, arguments, void 0, function* (provider, network, account, selectedMarket, marketInfo, blockNumber = 'latest') {
245
245
  const { marketId } = selectedMarket;
246
246
  const viewContract = MorphoMidnightViewContractViem(provider, network);
247
- const positionInfo = yield viewContract.read.getPositionInfo([marketId, account]);
247
+ const positionInfo = yield viewContract.read.getPositionInfo([marketId, account], setViemBlockNumber(blockNumber));
248
248
  const loanTokenData = marketInfo.assetsData[marketInfo.loanToken];
249
249
  const credit = assetAmountInEth(positionInfo.credit.toString(), marketInfo.loanToken);
250
250
  const creditUsd = new Dec(credit).mul(loanTokenData.price).toString();
@@ -8,10 +8,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import Dec from 'decimal.js';
11
- import { NetworkNumber } from '../types/common';
11
+ import { NetworkNumber, } from '../types/common';
12
12
  import { AaveMarkets, AaveV4Spokes, CompoundMarkets, CrvUsdMarkets, LiquityV2Markets, LlamaLendMarkets, MakerActiveIlks, MorphoBlueMarkets, MorphoMidnightMarkets, SparkMarkets, } from '../markets';
13
13
  import { AaveVersions, CompoundVersions, PortfolioProtocol, } from '../types';
14
- import { getViemProvider } from '../services/viem';
14
+ import { getBlockTimestamp, getViemProvider } from '../services/viem';
15
15
  import { ZERO_ADDRESS } from '../constants';
16
16
  import { _getAaveV2AccountData, _getAaveV2MarketsData } from '../aaveV2';
17
17
  import { _getAaveV3AccountData, _getAaveV3MarketData, getStakeAaveData } from '../aaveV3';
@@ -38,7 +38,7 @@ const positive = (value) => new Dec(value || '0').gt(0);
38
38
  const supported = (list, network) => (Object.values(list).filter((m) => m.chainIds.includes(network)));
39
39
  export function getCustomDeFiData(provider_1, network_1, defaultProvider_1, addresses_1) {
40
40
  return __awaiter(this, arguments, void 0, function* (provider, network, defaultProvider, addresses, options = {}) {
41
- var _a;
41
+ var _a, _b;
42
42
  const { protocols = Object.values(PortfolioProtocol), fetchStaking = false, fetchRewards = false, returnEmptyEModePositions = false, fetchFluidMarkets = false, isSim = false, } = options;
43
43
  // JSON-RPC body ends up ~4x the calldata cap; 250k keeps it under the ~2.5MB provider limit.
44
44
  const batchSize = (_a = options.batchSize) !== null && _a !== void 0 ? _a : (isSim ? 2000 : 250000);
@@ -47,6 +47,11 @@ export function getCustomDeFiData(provider_1, network_1, defaultProvider_1, addr
47
47
  const isFluidSupported = [NetworkNumber.Eth, NetworkNumber.Arb, NetworkNumber.Base, NetworkNumber.Plasma].includes(network);
48
48
  const client = getViemProvider(provider, network, { batch: { multicall: { batchSize } } });
49
49
  const defaultClient = getViemProvider(defaultProvider, network, { batch: { multicall: { batchSize } } });
50
+ // Every fetch below takes the block explicitly and passes it to each of its contract reads.
51
+ // Time-keyed sources (Merkl rewards) need the block's timestamp instead, resolved once here (no
52
+ // RPC call for 'latest') and handed to the market fetches so they don't each look it up.
53
+ const blockNumber = (_b = options.blockNumber) !== null && _b !== void 0 ? _b : 'latest';
54
+ const blockTimestamp = yield getBlockTimestamp(client, blockNumber);
50
55
  const aaveV3Markets = has(PortfolioProtocol.AaveV3)
51
56
  ? [AaveVersions.AaveV3, AaveVersions.AaveV3Lido, AaveVersions.AaveV3Etherfi].map((v) => AaveMarkets(network)[v]).filter((m) => m.chainIds.includes(network))
52
57
  : [];
@@ -138,22 +143,22 @@ export function getCustomDeFiData(provider_1, network_1, defaultProvider_1, addr
138
143
  }
139
144
  }))();
140
145
  yield Promise.allSettled([
141
- ...morphoMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.morphoMarketsData[m.value] = yield _getMorphoBluePortfolioMarketData(client, network, m); })),
142
- ...morphoMidnightMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.morphoMidnightMarketsData[m.value] = yield _getMorphoMidnightMarketData(client, network, m); })),
143
- ...compoundV3Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.compoundV3MarketsData[m.value] = yield _getCompoundV3MarketsData(client, network, m, defaultClient); })),
144
- ...sparkMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.sparkMarketsData[m.value] = yield _getSparkMarketsData(client, network, m); })),
145
- ...aaveV3Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.aaveV3MarketsData[m.value] = yield _getAaveV3MarketData(client, network, m); })),
146
- ...aaveV4Spokes.map((s) => __awaiter(this, void 0, void 0, function* () { markets.aaveV4SpokesData[s.value] = yield _getAaveV4SpokeData(client, network, s); })),
147
- ...aaveV2Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.aaveV2MarketsData[m.value] = yield _getAaveV2MarketsData(client, network, m); })),
148
- ...compoundV2Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.compoundV2MarketsData[m.value] = yield _getCompoundV2MarketsData(client, network); })),
149
- ...crvUsdMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.crvUsdMarketsData[m.value] = yield _getCurveUsdGlobalData(client, network, m); })),
150
- ...llamaLendMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.llamaLendMarketsData[m.value] = yield _getLlamaLendGlobalData(client, network, m); })),
151
- ...liquityV2Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.liquityV2MarketsData[m.value] = yield _getLiquityV2MarketData(client, network, m); })),
146
+ ...morphoMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.morphoMarketsData[m.value] = yield _getMorphoBluePortfolioMarketData(client, network, m, blockNumber); })),
147
+ ...morphoMidnightMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.morphoMidnightMarketsData[m.value] = yield _getMorphoMidnightMarketData(client, network, m, blockNumber); })),
148
+ ...compoundV3Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.compoundV3MarketsData[m.value] = yield _getCompoundV3MarketsData(client, network, m, defaultClient, blockNumber, blockTimestamp); })),
149
+ ...sparkMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.sparkMarketsData[m.value] = yield _getSparkMarketsData(client, network, m, blockNumber); })),
150
+ ...aaveV3Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.aaveV3MarketsData[m.value] = yield _getAaveV3MarketData(client, network, m, blockNumber, blockTimestamp); })),
151
+ ...aaveV4Spokes.map((s) => __awaiter(this, void 0, void 0, function* () { markets.aaveV4SpokesData[s.value] = yield _getAaveV4SpokeData(client, network, s, blockNumber, blockTimestamp); })),
152
+ ...aaveV2Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.aaveV2MarketsData[m.value] = yield _getAaveV2MarketsData(client, network, m, blockNumber); })),
153
+ ...compoundV2Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.compoundV2MarketsData[m.value] = yield _getCompoundV2MarketsData(client, network, blockNumber); })),
154
+ ...crvUsdMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.crvUsdMarketsData[m.value] = yield _getCurveUsdGlobalData(client, network, m, blockNumber); })),
155
+ ...llamaLendMarkets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.llamaLendMarketsData[m.value] = yield _getLlamaLendGlobalData(client, network, m, blockNumber); })),
156
+ ...liquityV2Markets.map((m) => __awaiter(this, void 0, void 0, function* () { markets.liquityV2MarketsData[m.value] = yield _getLiquityV2MarketData(client, network, m, blockNumber); })),
152
157
  (() => __awaiter(this, void 0, void 0, function* () {
153
158
  if (!fetchFluid || !fetchFluidMarkets)
154
159
  return;
155
160
  try {
156
- markets.fluidMarketsData = yield _getAllFluidMarketDataPortfolio(client, network);
161
+ markets.fluidMarketsData = yield _getAllFluidMarketDataPortfolio(client, network, blockNumber, blockTimestamp);
157
162
  }
158
163
  catch (error) {
159
164
  console.error('Error fetching Fluid markets data:', error);
@@ -163,7 +168,7 @@ export function getCustomDeFiData(provider_1, network_1, defaultProvider_1, addr
163
168
  if (!fetchMaker)
164
169
  return;
165
170
  try {
166
- markets.makerMarketsData = yield _getMakerIlksData(client, network, MakerActiveIlks);
171
+ markets.makerMarketsData = yield _getMakerIlksData(client, network, MakerActiveIlks, blockNumber);
167
172
  }
168
173
  catch (error) {
169
174
  console.error('Error fetching Maker ilks data:', error);
@@ -172,78 +177,78 @@ export function getCustomDeFiData(provider_1, network_1, defaultProvider_1, addr
172
177
  ...addresses.map((address) => __awaiter(this, void 0, void 0, function* () {
173
178
  if (!fetchMaker)
174
179
  return;
175
- makerCdps[lower(address)] = yield _getUserCdps(client, network, address);
180
+ makerCdps[lower(address)] = yield _getUserCdps(client, network, address, blockNumber);
176
181
  })),
177
- ...addresses.map((address) => fetchFluid && run(`Fluid positions for address ${address}`, () => _getUserPositionsPortfolio(client, network, address), (userPositions) => {
182
+ ...addresses.map((address) => fetchFluid && run(`Fluid positions for address ${address}`, () => _getUserPositionsPortfolio(client, network, address, blockNumber), (userPositions) => {
178
183
  for (const position of userPositions) {
179
184
  if (position.userData && positive(position.userData.suppliedUsd))
180
185
  positions[lower(address)].fluid.data[position.userData.nftId] = position.userData;
181
186
  }
182
187
  }, (err) => { positions[lower(address)].fluid = { error: err.error, data: {} }; })),
183
188
  ...(fetchStaking ? [
184
- ...addresses.map((address) => fetchFluid && run(`Fluid lend data for address ${address}`, () => _getAllUserEarnPositionsWithFTokens(client, network, address), (data) => { stakingPositions[lower(address)].fluid = data; }, (err) => { stakingPositions[lower(address)].fluid = err; })),
185
- ...addresses.map((address) => fetchLiquity && run(`Liquity staking data for address ${address}`, () => getLiquityStakingData(client, network, address), (data) => { stakingPositions[lower(address)].liquity = data; }, (err) => { stakingPositions[lower(address)].liquity = err; })),
186
- ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(`Aave V3 staking data for address ${address}`, () => getStakeAaveData(client, network, address), (data) => { stakingPositions[lower(address)].aaveV3 = data; }, (err) => { stakingPositions[lower(address)].aaveV3 = err; })),
187
- ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(`Umbrella staking data for address ${address}`, () => getUmbrellaData(client, network, address), (data) => { stakingPositions[lower(address)].umbrella = data; }, (err) => { stakingPositions[lower(address)].umbrella = err; })),
188
- ...perAddress(liquityV2StakingMarkets, (market, address) => run(`Liquity V2 staking data for address ${address}, market ${market.value}`, () => getLiquityV2Staking(client, network, market.value, address), (data) => { stakingPositions[lower(address)].liquityV2[market.value] = { error: '', data }; }, (err) => { stakingPositions[lower(address)].liquityV2[market.value] = err; })),
189
+ ...addresses.map((address) => fetchFluid && run(`Fluid lend data for address ${address}`, () => _getAllUserEarnPositionsWithFTokens(client, network, address, blockNumber), (data) => { stakingPositions[lower(address)].fluid = data; }, (err) => { stakingPositions[lower(address)].fluid = err; })),
190
+ ...addresses.map((address) => fetchLiquity && run(`Liquity staking data for address ${address}`, () => getLiquityStakingData(client, network, address, blockNumber), (data) => { stakingPositions[lower(address)].liquity = data; }, (err) => { stakingPositions[lower(address)].liquity = err; })),
191
+ ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(`Aave V3 staking data for address ${address}`, () => getStakeAaveData(client, network, address, blockNumber), (data) => { stakingPositions[lower(address)].aaveV3 = data; }, (err) => { stakingPositions[lower(address)].aaveV3 = err; })),
192
+ ...addresses.map((address) => has(PortfolioProtocol.AaveV3) && isMainnet && run(`Umbrella staking data for address ${address}`, () => getUmbrellaData(client, network, address, blockNumber), (data) => { stakingPositions[lower(address)].umbrella = data; }, (err) => { stakingPositions[lower(address)].umbrella = err; })),
193
+ ...perAddress(liquityV2StakingMarkets, (market, address) => run(`Liquity V2 staking data for address ${address}, market ${market.value}`, () => getLiquityV2Staking(client, network, market.value, address, blockNumber), (data) => { stakingPositions[lower(address)].liquityV2[market.value] = { error: '', data }; }, (err) => { stakingPositions[lower(address)].liquityV2[market.value] = err; })),
189
194
  ] : []),
190
195
  ...(fetchRewards ? [
191
- batchRewards('king', 'King rewards data', () => getKingRewards(client, network, addresses), isMainnet),
192
- batchRewards('uniswap', 'Uniswap rewards data', () => getUniswapRewards(client, network, addresses), isMainnet),
193
- batchRewards('spk', 'Spark Airdrop rewards data', () => fetchSparkAirdropRewards(client, network, addresses), isMainnet && has(PortfolioProtocol.Spark)),
196
+ batchRewards('king', 'King rewards data', () => getKingRewards(client, network, addresses, blockNumber), isMainnet),
197
+ batchRewards('uniswap', 'Uniswap rewards data', () => getUniswapRewards(client, network, addresses, blockNumber), isMainnet),
198
+ batchRewards('spk', 'Spark Airdrop rewards data', () => fetchSparkAirdropRewards(client, network, addresses, blockNumber), isMainnet && has(PortfolioProtocol.Spark)),
194
199
  batchRewards('ethena', 'Ethena Airdrop rewards data', () => fetchEthenaAirdropRewards(addresses), isMainnet),
195
200
  ...addresses.map((address) => run(`Merkl rewards data for address ${address}`, () => getMerklUnclaimedRewards(address, network), (data) => { rewardsData[lower(address)].merkl = { error: '', data }; }, (err) => { rewardsData[lower(address)].merkl = err; })),
196
- ...perAddress(aaveV3Markets, (market, address) => run(`Aave V3 rewards data for address ${address}, market ${market.value}`, () => getUnclaimedRewardsForAllMarkets(client, network, address, market.providerAddress), (data) => { rewardsData[lower(address)].aaveV3[market.value] = { error: '', data }; }, (err) => { rewardsData[lower(address)].aaveV3[market.value] = err; })),
201
+ ...perAddress(aaveV3Markets, (market, address) => run(`Aave V3 rewards data for address ${address}, market ${market.value}`, () => getUnclaimedRewardsForAllMarkets(client, network, address, market.providerAddress, blockNumber), (data) => { rewardsData[lower(address)].aaveV3[market.value] = { error: '', data }; }, (err) => { rewardsData[lower(address)].aaveV3[market.value] = err; })),
197
202
  ...perAddress(sparkMarkets, (market, address) => {
198
203
  if (!isMainnet) {
199
204
  rewardsData[lower(address)].spark[market.value] = { error: '', data: [] };
200
205
  return Promise.resolve();
201
206
  }
202
- return run(`Spark rewards data for address ${address}, market ${market.value}`, () => fetchSparkRewards(client, network, address, market.providerAddress), (data) => { rewardsData[lower(address)].spark[market.value] = { error: '', data }; }, (err) => { rewardsData[lower(address)].spark[market.value] = err; });
207
+ return run(`Spark rewards data for address ${address}, market ${market.value}`, () => fetchSparkRewards(client, network, address, market.providerAddress, blockNumber), (data) => { rewardsData[lower(address)].spark[market.value] = { error: '', data }; }, (err) => { rewardsData[lower(address)].spark[market.value] = err; });
203
208
  }),
204
209
  ] : []),
205
210
  ]);
206
211
  yield Promise.all([
207
- ...perAddress(aaveV3Markets, (market, address) => run(`AaveV3 account data for address ${address} on market ${market.value}`, () => _getAaveV3AccountData(client, network, address, Object.assign({ selectedMarket: market }, markets.aaveV3MarketsData[market.value])), (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd))
212
+ ...perAddress(aaveV3Markets, (market, address) => run(`AaveV3 account data for address ${address} on market ${market.value}`, () => _getAaveV3AccountData(client, network, address, Object.assign({ selectedMarket: market }, markets.aaveV3MarketsData[market.value]), blockNumber), (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd))
208
213
  positions[lower(address)].aaveV3[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].aaveV3[market.value] = err; })),
209
- ...perAddress(sparkMarkets, (market, address) => run(`Spark account data for address ${address} on market ${market.value}`, () => _getSparkAccountData(client, network, address, { selectedMarket: market, assetsData: markets.sparkMarketsData[market.value].assetsData, eModeCategoriesData: markets.sparkMarketsData[market.value].eModeCategoriesData }), (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd))
214
+ ...perAddress(sparkMarkets, (market, address) => run(`Spark account data for address ${address} on market ${market.value}`, () => _getSparkAccountData(client, network, address, { selectedMarket: market, assetsData: markets.sparkMarketsData[market.value].assetsData, eModeCategoriesData: markets.sparkMarketsData[market.value].eModeCategoriesData }, blockNumber), (data) => { if (returnEmptyEModePositions || positive(data.suppliedUsd))
210
215
  positions[lower(address)].spark[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].spark[market.value] = err; })),
211
- ...perAddress(aaveV4Spokes, (spoke, address) => run(`AaveV4 account data for address ${address} on spoke ${spoke.value}`, () => _getAaveV4AccountData(client, network, markets.aaveV4SpokesData[spoke.value], address), (data) => { if (positive(data.suppliedUsd))
216
+ ...perAddress(aaveV4Spokes, (spoke, address) => run(`AaveV4 account data for address ${address} on spoke ${spoke.value}`, () => _getAaveV4AccountData(client, network, markets.aaveV4SpokesData[spoke.value], address, blockNumber), (data) => { if (positive(data.suppliedUsd))
212
217
  positions[lower(address)].aaveV4[spoke.value] = { error: '', data }; }, (err) => { positions[lower(address)].aaveV4[spoke.value] = err; })),
213
- ...perAddress(morphoMarkets, (market, address) => run(`MorphoBlue account data for address ${address} on market ${market.value}`, () => _getMorphoBlueAccountData(client, network, address, market, markets.morphoMarketsData[market.value]), (data) => { if (positive(data.suppliedUsd))
218
+ ...perAddress(morphoMarkets, (market, address) => run(`MorphoBlue account data for address ${address} on market ${market.value}`, () => _getMorphoBlueAccountData(client, network, address, market, markets.morphoMarketsData[market.value], blockNumber), (data) => { if (positive(data.suppliedUsd))
214
219
  positions[lower(address)].morphoBlue[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].morphoBlue[market.value] = err; })),
215
- ...(fetchStaking ? perAddress(morphoMarkets, (market, address) => run(`MorphoBlue earn data for address ${address} on market ${market.value}`, () => getMorphoEarn(client, network, address, market, markets.morphoMarketsData[market.value]), (data) => { if (data && positive(data.amount))
220
+ ...(fetchStaking ? perAddress(morphoMarkets, (market, address) => run(`MorphoBlue earn data for address ${address} on market ${market.value}`, () => getMorphoEarn(client, network, address, market, markets.morphoMarketsData[market.value], blockNumber), (data) => { if (data && positive(data.amount))
216
221
  stakingPositions[lower(address)].morphoBlue[market.value] = { error: '', data }; }, (err) => { stakingPositions[lower(address)].morphoBlue[market.value] = err; })) : []),
217
222
  ...perAddress(morphoMidnightMarkets, (market, address) => {
218
223
  var _a;
219
224
  if (!((_a = markets.morphoMidnightMarketsData[market.value]) === null || _a === void 0 ? void 0 : _a.isCreated))
220
225
  return Promise.resolve();
221
- return run(`MorphoMidnight account data for address ${address} on market ${market.value}`, () => _getMorphoMidnightAccountData(client, network, address, market, markets.morphoMidnightMarketsData[market.value]), (data) => { if (positive(data.suppliedUsd))
226
+ return run(`MorphoMidnight account data for address ${address} on market ${market.value}`, () => _getMorphoMidnightAccountData(client, network, address, market, markets.morphoMidnightMarketsData[market.value], blockNumber), (data) => { if (positive(data.suppliedUsd))
222
227
  positions[lower(address)].morphoMidnight[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].morphoMidnight[market.value] = err; });
223
228
  }),
224
- ...perAddress(compoundV3Markets, (market, address) => run(`CompoundV3 account data for address ${address} on market ${market.value}`, () => _getCompoundV3AccountData(client, network, address, ZERO_ADDRESS, { selectedMarket: market, assetsData: markets.compoundV3MarketsData[market.value].assetsData }), (data) => { if (positive(data.suppliedUsd))
229
+ ...perAddress(compoundV3Markets, (market, address) => run(`CompoundV3 account data for address ${address} on market ${market.value}`, () => _getCompoundV3AccountData(client, network, address, ZERO_ADDRESS, { selectedMarket: market, assetsData: markets.compoundV3MarketsData[market.value].assetsData }, blockNumber), (data) => { if (positive(data.suppliedUsd))
225
230
  positions[lower(address)].compoundV3[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].compoundV3[market.value] = err; })),
226
- ...perAddress(compoundV2Markets, (market, address) => run(`CompoundV2 account data for address ${address}`, () => _getCompoundV2AccountData(client, network, address, markets.compoundV2MarketsData[market.value].assetsData), (data) => { if (positive(data.suppliedUsd))
231
+ ...perAddress(compoundV2Markets, (market, address) => run(`CompoundV2 account data for address ${address}`, () => _getCompoundV2AccountData(client, network, address, markets.compoundV2MarketsData[market.value].assetsData, blockNumber), (data) => { if (positive(data.suppliedUsd))
227
232
  positions[lower(address)].compoundV2[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].compoundV2[market.value] = err; })),
228
- ...perAddress(aaveV2Markets, (market, address) => run(`AaveV2 account data for address ${address}`, () => _getAaveV2AccountData(client, network, address, markets.aaveV2MarketsData[market.value].assetsData, market), (data) => { if (positive(data.suppliedUsd))
233
+ ...perAddress(aaveV2Markets, (market, address) => run(`AaveV2 account data for address ${address}`, () => _getAaveV2AccountData(client, network, address, markets.aaveV2MarketsData[market.value].assetsData, market, blockNumber), (data) => { if (positive(data.suppliedUsd))
229
234
  positions[lower(address)].aaveV2[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].aaveV2[market.value] = err; })),
230
- ...perAddress(crvUsdMarkets, (market, address) => run(`Curve USD account data for address ${address} on market ${market.value}`, () => _getCurveUsdUserData(client, network, address, market, markets.crvUsdMarketsData[market.value].activeBand, markets.crvUsdMarketsData[market.value].borrowRate), (data) => { if (positive(data.suppliedUsd) || positive(data.borrowedUsd))
235
+ ...perAddress(crvUsdMarkets, (market, address) => run(`Curve USD account data for address ${address} on market ${market.value}`, () => _getCurveUsdUserData(client, network, address, market, markets.crvUsdMarketsData[market.value].activeBand, markets.crvUsdMarketsData[market.value].borrowRate, blockNumber), (data) => { if (positive(data.suppliedUsd) || positive(data.borrowedUsd))
231
236
  positions[lower(address)].crvUsd[market.value] = { error: '', data }; }, (err) => { positions[lower(address)].crvUsd[market.value] = err; })),
232
- ...perAddress(llamaLendMarkets, (market, address) => run(`LlamaLend account data for address ${address} on market ${market.value}`, () => _getLlamaLendUserData(client, network, address, market, markets.llamaLendMarketsData[market.value]), (data) => {
237
+ ...perAddress(llamaLendMarkets, (market, address) => run(`LlamaLend account data for address ${address} on market ${market.value}`, () => _getLlamaLendUserData(client, network, address, market, markets.llamaLendMarketsData[market.value], blockNumber), (data) => {
233
238
  if (positive(data.suppliedUsd) || positive(data.borrowedUsd)) {
234
239
  positions[lower(address)].llamaLend[market.value] = { error: '', data: Object.assign(Object.assign({}, data), { borrowRate: markets.llamaLendMarketsData[market.value].borrowRate }) };
235
240
  }
236
241
  }, (err) => { positions[lower(address)].llamaLend[market.value] = err; })),
237
- ...addresses.map((address) => (makerCdps[lower(address)] || []).map((cdpInfo) => run(`Maker CDP data for address ${address} with ID ${cdpInfo.id}`, () => _getMakerCdpData(client, network, cdpInfo, markets.makerMarketsData[cdpInfo.ilkLabel]), (data) => { if (data)
242
+ ...addresses.map((address) => (makerCdps[lower(address)] || []).map((cdpInfo) => run(`Maker CDP data for address ${address} with ID ${cdpInfo.id}`, () => _getMakerCdpData(client, network, cdpInfo, markets.makerMarketsData[cdpInfo.ilkLabel], blockNumber), (data) => { if (data)
238
243
  positions[lower(address)].maker[cdpInfo.id] = { error: '', data }; }, (err) => { positions[lower(address)].maker[cdpInfo.id] = err; }))).flat(),
239
- ...addresses.map((address) => fetchLiquity && run(`Liquity trove info for address ${address}`, () => _getLiquityTroveInfo(client, network, address), (data) => { if (positive(data.collateral))
244
+ ...addresses.map((address) => fetchLiquity && run(`Liquity trove info for address ${address}`, () => _getLiquityTroveInfo(client, network, address, blockNumber), (data) => { if (positive(data.collateral))
240
245
  positions[lower(address)].liquity = { error: '', data }; }, (err) => { positions[lower(address)].liquity = err; })),
241
246
  ...(fetchStaking && has(PortfolioProtocol.LiquityV2) ? addresses.map((address) => {
242
247
  if (!isMainnet) {
243
248
  stakingPositions[lower(address)].liquityV2SBoldYBold = { error: '', data: null };
244
249
  return Promise.resolve();
245
250
  }
246
- return run(`sBold/yBold data for address ${address}`, () => getLiquitySAndYBold(client, network, stakingPositions[lower(address)].liquityV2, address), (data) => { stakingPositions[lower(address)].liquityV2SBoldYBold = { error: '', data }; }, (err) => { stakingPositions[lower(address)].liquityV2SBoldYBold = err; });
251
+ return run(`sBold/yBold data for address ${address}`, () => getLiquitySAndYBold(client, network, stakingPositions[lower(address)].liquityV2, address, blockNumber), (data) => { stakingPositions[lower(address)].liquityV2SBoldYBold = { error: '', data }; }, (err) => { stakingPositions[lower(address)].liquityV2SBoldYBold = err; });
247
252
  }) : []),
248
253
  ]);
249
254
  return {
@@ -1,6 +1,40 @@
1
- import { MerklOpportunity } from '../types';
1
+ import { MerklCampaignListItem, MerklOpportunity } from '../types';
2
2
  /**
3
- * Fetches every page matching the query. Merkl returns 20 opportunities by default, so omitting
3
+ * Fetches every opportunity matching the query. Merkl returns 20 opportunities by default, so omitting
4
4
  * `items` and advancing `page` avoids imposing a client-side maximum on the result set.
5
5
  */
6
6
  export declare const fetchAllMerklOpportunities: (query: Record<string, string>) => Promise<MerklOpportunity[]>;
7
+ /** Fetches every campaign matching the query, e.g. `{ mainProtocolId: 'aave', status: 'LIVE,PAST' }`. */
8
+ export declare const fetchAllMerklCampaigns: (query: Record<string, string>) => Promise<MerklCampaignListItem[]>;
9
+ /**
10
+ * Fetches the opportunities with the given Merkl-internal ids, regardless of their current status.
11
+ * Ids Merkl no longer serves (hidden or test campaigns) are simply absent from the result.
12
+ */
13
+ export declare const fetchMerklOpportunitiesByIds: (ids: string[]) => Promise<MerklOpportunity[]>;
14
+ /**
15
+ * Returns the reward APR Merkl recorded for the opportunity at the given unix timestamp (seconds),
16
+ * or `undefined` when no campaign was computing for it then. Records are hourly buckets keyed by
17
+ * their start, newest first, so the first bucket at or before the timestamp carries the value in
18
+ * force at that moment; the window is a day wide to tolerate computation gaps.
19
+ */
20
+ export declare const fetchMerklOpportunityAprAt: (opportunityId: string, timestamp: number) => Promise<number | undefined>;
21
+ /**
22
+ * Reconstructs the opportunities that were live at `timestamp` (unix seconds), shaped like the
23
+ * live listing so the per-protocol reward mappers can consume either without knowing which they got:
24
+ * 1. campaigns for the protocol (and chain, when the query names one) whose [start, end] covers
25
+ * the timestamp identify the opportunities that were rewarded then — the live listing can't,
26
+ * since campaigns live then are mostly PAST now and ones live now didn't exist then;
27
+ * 2. those opportunities are loaded by id (works for PAST ones too) and narrowed to `query.type`;
28
+ * 3. each one's `apr` is replaced with the value Merkl recorded at the timestamp, and ones with no
29
+ * record then are dropped, since nothing was being computed for them.
30
+ * `status` is forced to LIVE so status filters downstream keep working, `campaigns` carries the
31
+ * covering campaigns, and a reward token breakdown is synthesized from the campaign's reward token
32
+ * when Merkl no longer serves one for the opportunity (it drops them once an opportunity is PAST).
33
+ * `query.status` is ignored: it describes the present, not the requested moment.
34
+ */
35
+ export declare const fetchMerklOpportunitiesAt: (query: Record<string, string>, timestamp: number) => Promise<MerklOpportunity[]>;
36
+ /**
37
+ * Live opportunities when no timestamp is given, otherwise the opportunities as they were at that
38
+ * unix timestamp (seconds) — see `fetchMerklOpportunitiesAt`.
39
+ */
40
+ export declare const fetchMerklOpportunities: (query: Record<string, string>, asOfTimestamp?: number) => Promise<MerklOpportunity[]>;