@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.
- package/cjs/aaveV2/index.d.ts +4 -4
- package/cjs/aaveV2/index.js +7 -7
- package/cjs/aaveV3/index.d.ts +4 -3
- package/cjs/aaveV3/index.js +14 -10
- package/cjs/aaveV3/merkl.d.ts +5 -1
- package/cjs/aaveV3/merkl.js +8 -3
- package/cjs/aaveV4/index.d.ts +4 -3
- package/cjs/aaveV4/index.js +19 -16
- package/cjs/aaveV4/merkl.d.ts +10 -2
- package/cjs/aaveV4/merkl.js +15 -6
- package/cjs/claiming/aaveV3.d.ts +2 -2
- package/cjs/claiming/aaveV3.js +5 -4
- package/cjs/claiming/king.d.ts +2 -2
- package/cjs/claiming/king.js +3 -2
- package/cjs/claiming/spark.d.ts +3 -3
- package/cjs/claiming/spark.js +8 -7
- package/cjs/claiming/uniswap.d.ts +2 -2
- package/cjs/claiming/uniswap.js +3 -2
- package/cjs/compoundV2/index.d.ts +4 -4
- package/cjs/compoundV2/index.js +9 -9
- package/cjs/compoundV3/index.d.ts +5 -4
- package/cjs/compoundV3/index.js +17 -13
- package/cjs/compoundV3/merkl.d.ts +1 -1
- package/cjs/compoundV3/merkl.js +2 -5
- package/cjs/curveUsd/index.d.ts +5 -5
- package/cjs/curveUsd/index.js +17 -17
- package/cjs/fluid/index.d.ts +23 -22
- package/cjs/fluid/index.js +75 -72
- package/cjs/fluid/merkl.d.ts +5 -3
- package/cjs/fluid/merkl.js +11 -6
- package/cjs/liquity/index.d.ts +4 -4
- package/cjs/liquity/index.js +23 -23
- package/cjs/liquityV2/index.d.ts +10 -10
- package/cjs/liquityV2/index.js +59 -59
- package/cjs/llamaLend/index.d.ts +5 -5
- package/cjs/llamaLend/index.js +13 -13
- package/cjs/maker/index.d.ts +6 -6
- package/cjs/maker/index.js +16 -16
- package/cjs/morphoBlue/index.d.ts +7 -7
- package/cjs/morphoBlue/index.js +28 -26
- package/cjs/morphoBlue/merkl.d.ts +5 -3
- package/cjs/morphoBlue/merkl.js +6 -8
- package/cjs/morphoMidnight/index.d.ts +5 -5
- package/cjs/morphoMidnight/index.js +18 -18
- package/cjs/portfolio/customDeFiData.js +45 -40
- package/cjs/services/merkl.d.ts +36 -2
- package/cjs/services/merkl.js +142 -19
- package/cjs/services/priceService.d.ts +12 -12
- package/cjs/services/priceService.js +30 -29
- package/cjs/services/viem.d.ts +10 -2
- package/cjs/services/viem.js +27 -1
- package/cjs/spark/index.d.ts +4 -4
- package/cjs/spark/index.js +9 -9
- package/cjs/types/merkl.d.ts +18 -0
- package/cjs/types/portfolio.d.ts +2 -0
- package/cjs/umbrella/index.d.ts +2 -2
- package/cjs/umbrella/index.js +5 -4
- package/esm/aaveV2/index.d.ts +4 -4
- package/esm/aaveV2/index.js +8 -8
- package/esm/aaveV3/index.d.ts +4 -3
- package/esm/aaveV3/index.js +15 -11
- package/esm/aaveV3/merkl.d.ts +5 -1
- package/esm/aaveV3/merkl.js +9 -4
- package/esm/aaveV4/index.d.ts +4 -3
- package/esm/aaveV4/index.js +20 -17
- package/esm/aaveV4/merkl.d.ts +10 -2
- package/esm/aaveV4/merkl.js +16 -7
- package/esm/claiming/aaveV3.d.ts +2 -2
- package/esm/claiming/aaveV3.js +5 -4
- package/esm/claiming/king.d.ts +2 -2
- package/esm/claiming/king.js +3 -2
- package/esm/claiming/spark.d.ts +3 -3
- package/esm/claiming/spark.js +8 -7
- package/esm/claiming/uniswap.d.ts +2 -2
- package/esm/claiming/uniswap.js +3 -2
- package/esm/compoundV2/index.d.ts +4 -4
- package/esm/compoundV2/index.js +9 -9
- package/esm/compoundV3/index.d.ts +5 -4
- package/esm/compoundV3/index.js +19 -15
- package/esm/compoundV3/merkl.d.ts +1 -1
- package/esm/compoundV3/merkl.js +3 -6
- package/esm/curveUsd/index.d.ts +5 -5
- package/esm/curveUsd/index.js +17 -17
- package/esm/fluid/index.d.ts +23 -22
- package/esm/fluid/index.js +76 -73
- package/esm/fluid/merkl.d.ts +5 -3
- package/esm/fluid/merkl.js +12 -7
- package/esm/liquity/index.d.ts +4 -4
- package/esm/liquity/index.js +23 -23
- package/esm/liquityV2/index.d.ts +10 -10
- package/esm/liquityV2/index.js +60 -60
- package/esm/llamaLend/index.d.ts +5 -5
- package/esm/llamaLend/index.js +13 -13
- package/esm/maker/index.d.ts +6 -6
- package/esm/maker/index.js +16 -16
- package/esm/morphoBlue/index.d.ts +7 -7
- package/esm/morphoBlue/index.js +29 -27
- package/esm/morphoBlue/merkl.d.ts +5 -3
- package/esm/morphoBlue/merkl.js +7 -9
- package/esm/morphoMidnight/index.d.ts +5 -5
- package/esm/morphoMidnight/index.js +18 -18
- package/esm/portfolio/customDeFiData.js +47 -42
- package/esm/services/merkl.d.ts +36 -2
- package/esm/services/merkl.js +136 -18
- package/esm/services/priceService.d.ts +12 -12
- package/esm/services/priceService.js +31 -30
- package/esm/services/viem.d.ts +10 -2
- package/esm/services/viem.js +25 -0
- package/esm/spark/index.d.ts +4 -4
- package/esm/spark/index.js +10 -10
- package/esm/types/merkl.d.ts +18 -0
- package/esm/types/portfolio.d.ts +2 -0
- package/esm/umbrella/index.d.ts +2 -2
- package/esm/umbrella/index.js +5 -4
- package/package.json +1 -1
- package/src/aaveV2/index.ts +7 -7
- package/src/aaveV3/index.ts +15 -11
- package/src/aaveV3/merkl.ts +9 -4
- package/src/aaveV4/index.ts +19 -16
- package/src/aaveV4/merkl.ts +16 -7
- package/src/claiming/aaveV3.ts +5 -3
- package/src/claiming/king.ts +6 -3
- package/src/claiming/spark.ts +9 -6
- package/src/claiming/uniswap.ts +4 -3
- package/src/compoundV2/index.ts +10 -9
- package/src/compoundV3/index.ts +20 -14
- package/src/compoundV3/merkl.ts +5 -4
- package/src/curveUsd/index.ts +19 -17
- package/src/fluid/index.ts +88 -70
- package/src/fluid/merkl.ts +12 -7
- package/src/liquity/index.ts +23 -23
- package/src/liquityV2/index.ts +64 -56
- package/src/llamaLend/index.ts +15 -13
- package/src/maker/index.ts +19 -16
- package/src/morphoBlue/index.ts +23 -20
- package/src/morphoBlue/merkl.ts +9 -6
- package/src/morphoMidnight/index.ts +13 -13
- package/src/portfolio/customDeFiData.ts +48 -41
- package/src/services/merkl.ts +152 -19
- package/src/services/priceService.ts +33 -30
- package/src/services/viem.ts +16 -0
- package/src/spark/index.ts +11 -8
- package/src/types/merkl.ts +20 -0
- package/src/types/portfolio.ts +2 -0
- package/src/umbrella/index.ts +6 -5
package/src/aaveV2/index.ts
CHANGED
|
@@ -18,13 +18,13 @@ import { aaveAnyGetAggregatedPositionData } from '../helpers/aaveHelpers';
|
|
|
18
18
|
import { getEthPrice } from '../services/priceService';
|
|
19
19
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
20
20
|
|
|
21
|
-
export const _getAaveV2MarketsData = async (provider: Client, network: NetworkNumber, selectedMarket: AaveMarketInfo) => {
|
|
21
|
+
export const _getAaveV2MarketsData = async (provider: Client, network: NetworkNumber, selectedMarket: AaveMarketInfo, blockNumber: Blockish = 'latest') => {
|
|
22
22
|
const _addresses = selectedMarket.assets.map(a => getAssetInfo(ethToWeth(a)).address);
|
|
23
23
|
const loanInfoContract = AaveLoanInfoV2ContractViem(provider, network);
|
|
24
24
|
const marketAddress = selectedMarket.providerAddress;
|
|
25
25
|
const [loanInfo, ethPrice] = await Promise.all([
|
|
26
|
-
loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses as EthAddress[]]),
|
|
27
|
-
getEthPrice(provider),
|
|
26
|
+
loanInfoContract.read.getFullTokensInfo([marketAddress, _addresses as EthAddress[]], setViemBlockNumber(blockNumber)),
|
|
27
|
+
getEthPrice(provider, blockNumber),
|
|
28
28
|
]);
|
|
29
29
|
const markets: AaveV2AssetData[] = loanInfo
|
|
30
30
|
.map((market, i) => ({
|
|
@@ -87,7 +87,7 @@ export const _getAaveV2MarketsData = async (provider: Client, network: NetworkNu
|
|
|
87
87
|
return { assetsData: payload };
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
export const getAaveV2MarketsData = async (provider: EthereumProvider, network: NetworkNumber, selectedMarket: AaveMarketInfo) => _getAaveV2MarketsData(getViemProvider(provider, network), network, selectedMarket);
|
|
90
|
+
export const getAaveV2MarketsData = async (provider: EthereumProvider, network: NetworkNumber, selectedMarket: AaveMarketInfo, blockNumber: Blockish = 'latest') => _getAaveV2MarketsData(getViemProvider(provider, network), network, selectedMarket, blockNumber);
|
|
91
91
|
|
|
92
92
|
export const _getAaveV2AccountBalances = async (provider: Client, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => {
|
|
93
93
|
const balances = await getAaveLikeBalances(provider, network, block, addressMapping, address, AAVE_V2, 'AaveLoanInfoV2');
|
|
@@ -100,7 +100,7 @@ export const _getAaveV2AccountBalances = async (provider: Client, network: Netwo
|
|
|
100
100
|
|
|
101
101
|
export const getAaveV2AccountBalances = async (provider: EthereumProvider, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress): Promise<PositionBalances> => _getAaveV2AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address);
|
|
102
102
|
|
|
103
|
-
export const _getAaveV2AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, assetsData: AaveV2AssetsData, market: AaveMarketInfo): Promise<AaveV2PositionData> => {
|
|
103
|
+
export const _getAaveV2AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, assetsData: AaveV2AssetsData, market: AaveMarketInfo, blockNumber: Blockish = 'latest'): Promise<AaveV2PositionData> => {
|
|
104
104
|
if (!address) throw new Error('Address is required');
|
|
105
105
|
|
|
106
106
|
let payload: AaveV2PositionData = {
|
|
@@ -111,7 +111,7 @@ export const _getAaveV2AccountData = async (provider: Client, network: NetworkNu
|
|
|
111
111
|
const loanInfoContract = AaveLoanInfoV2ContractViem(provider, network);
|
|
112
112
|
const marketAddress = market.providerAddress;
|
|
113
113
|
const _addresses = market.assets.map(a => getAssetInfo(ethToWeth(a)).address);
|
|
114
|
-
const loanInfo = await loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses as EthAddress[]]);
|
|
114
|
+
const loanInfo = await loanInfoContract.read.getTokenBalances([marketAddress, address, _addresses as EthAddress[]], setViemBlockNumber(blockNumber));
|
|
115
115
|
const usedAssets = {} as AaveV2UsedAssets;
|
|
116
116
|
loanInfo.forEach((_tokenInfo, i) => {
|
|
117
117
|
const asset = market.assets[i];
|
|
@@ -193,7 +193,7 @@ export const _getAaveV2AccountData = async (provider: Client, network: NetworkNu
|
|
|
193
193
|
return payload;
|
|
194
194
|
};
|
|
195
195
|
|
|
196
|
-
export const getAaveV2AccountData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, assetsData: AaveV2AssetsData, market: AaveMarketInfo): Promise<AaveV2PositionData> => _getAaveV2AccountData(getViemProvider(provider, network), network, address, assetsData, market);
|
|
196
|
+
export const getAaveV2AccountData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, assetsData: AaveV2AssetsData, market: AaveMarketInfo, blockNumber: Blockish = 'latest'): Promise<AaveV2PositionData> => _getAaveV2AccountData(getViemProvider(provider, network), network, address, assetsData, market, blockNumber);
|
|
197
197
|
|
|
198
198
|
export const getAaveV2FullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, market: AaveMarketInfo): Promise<AaveV2PositionData> => {
|
|
199
199
|
const marketData = await getAaveV2MarketsData(provider, network, market);
|
package/src/aaveV3/index.ts
CHANGED
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
PositionBalances,
|
|
43
43
|
HexString,
|
|
44
44
|
} from '../types/common';
|
|
45
|
-
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
45
|
+
import { getBlockTimestamp, getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
46
46
|
import { getMeritCampaigns } from './merit';
|
|
47
47
|
import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './merkl';
|
|
48
48
|
import { getSghoData } from './sgho';
|
|
@@ -81,7 +81,8 @@ export const aaveV3EmodeCategoriesMapping = (extractedState: any, usedAssets: Aa
|
|
|
81
81
|
return categoriesMapping;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
/** `blockTimestamp` (unix seconds) is the historical block's timestamp when already known; otherwise it is read from the block. */
|
|
85
|
+
export async function _getAaveV3MarketData(provider: Client, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest', blockTimestamp?: number): Promise<AaveV3MarketData> {
|
|
85
86
|
const _addresses = market.assets.map(a => getAssetInfo(getWrappedNativeAssetFromUnwrapped(a), network).address);
|
|
86
87
|
|
|
87
88
|
const loanInfoContract = AaveV3ViewContractViem(provider, network);
|
|
@@ -100,12 +101,15 @@ export async function _getAaveV3MarketData(provider: Client, network: NetworkNum
|
|
|
100
101
|
[marketAddress, addresses],
|
|
101
102
|
setViemBlockNumber(blockNumber),
|
|
102
103
|
))).then((loanInfoChunks) => loanInfoChunks.flat());
|
|
104
|
+
// Merkl rewards are keyed by time, so a historical block resolves to its timestamp first (one
|
|
105
|
+
// RPC call unless given, none for 'latest') and the rewards in force at that moment are attached.
|
|
106
|
+
const merkleRewardsPromise = getBlockTimestamp(provider, blockNumber, blockTimestamp).then((asOfTimestamp) => getMerkleCampaigns(network, asOfTimestamp));
|
|
103
107
|
// eslint-disable-next-line prefer-const
|
|
104
108
|
let [loanInfo, eModesInfo, rewardInfo, merkleRewardsMap, meritRewardsMap] = await Promise.all([
|
|
105
109
|
loanInfoPromise,
|
|
106
110
|
loanInfoContract.read.getAllEmodes([marketAddress], setViemBlockNumber(blockNumber)),
|
|
107
111
|
networksWithIncentives.includes(network) ? aaveIncentivesContract.read.getReservesIncentivesData([marketAddress], setViemBlockNumber(blockNumber)) : null,
|
|
108
|
-
|
|
112
|
+
merkleRewardsPromise,
|
|
109
113
|
getMeritCampaigns(network, market.value),
|
|
110
114
|
]);
|
|
111
115
|
// same break logic as view contract
|
|
@@ -356,8 +360,8 @@ export async function _getAaveV3MarketData(provider: Client, network: NetworkNum
|
|
|
356
360
|
return { assetsData: payload, eModeCategoriesData };
|
|
357
361
|
}
|
|
358
362
|
|
|
359
|
-
export async function getAaveV3MarketData(provider: EthereumProvider, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV3MarketData> {
|
|
360
|
-
return _getAaveV3MarketData(getViemProvider(provider, network), network, market, blockNumber);
|
|
363
|
+
export async function getAaveV3MarketData(provider: EthereumProvider, network: NetworkNumber, market: AaveMarketInfo, blockNumber: 'latest' | number = 'latest', blockTimestamp?: number): Promise<AaveV3MarketData> {
|
|
364
|
+
return _getAaveV3MarketData(getViemProvider(provider, network), network, market, blockNumber, blockTimestamp);
|
|
361
365
|
}
|
|
362
366
|
|
|
363
367
|
export const EMPTY_AAVE_DATA = {
|
|
@@ -852,7 +856,7 @@ export const fetchYearlyMeritApyForStakingGho = async () => {
|
|
|
852
856
|
}
|
|
853
857
|
};
|
|
854
858
|
|
|
855
|
-
export const getStakeAaveData = async (provider: Client, network: NetworkNumber, address: EthAddress) => {
|
|
859
|
+
export const getStakeAaveData = async (provider: Client, network: NetworkNumber, address: EthAddress, blockNumber: Blockish = 'latest') => {
|
|
856
860
|
const stkGhoAddress = getAssetInfo('stkGHO').address as HexString;
|
|
857
861
|
const stkAaveAddress = getAssetInfo('stkAAVE').address as HexString;
|
|
858
862
|
|
|
@@ -862,11 +866,11 @@ export const getStakeAaveData = async (provider: Client, network: NetworkNumber,
|
|
|
862
866
|
|
|
863
867
|
|
|
864
868
|
const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy, sgho] = await Promise.all([
|
|
865
|
-
AaveIncentivesController.read.getRewardsBalance([REWARDABLE_ASSETS, address]),
|
|
866
|
-
stkAAVE.read.assets([stkAaveAddress]),
|
|
867
|
-
stkAAVE.read.balanceOf([address]),
|
|
868
|
-
stkAAVE.read.totalSupply(),
|
|
869
|
-
stkGHO.read.balanceOf([address]),
|
|
869
|
+
AaveIncentivesController.read.getRewardsBalance([REWARDABLE_ASSETS, address], setViemBlockNumber(blockNumber)),
|
|
870
|
+
stkAAVE.read.assets([stkAaveAddress], setViemBlockNumber(blockNumber)),
|
|
871
|
+
stkAAVE.read.balanceOf([address], setViemBlockNumber(blockNumber)),
|
|
872
|
+
stkAAVE.read.totalSupply(setViemBlockNumber(blockNumber)),
|
|
873
|
+
stkGHO.read.balanceOf([address], setViemBlockNumber(blockNumber)),
|
|
870
874
|
fetchYearlyMeritApyForStakingGho(),
|
|
871
875
|
getSghoData(network, address),
|
|
872
876
|
]);
|
package/src/aaveV3/merkl.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { aprToApy } from '../moneymarket';
|
|
2
|
-
import {
|
|
2
|
+
import { fetchMerklOpportunities } from '../services/merkl';
|
|
3
3
|
import { wethToEth } from '../services/utils';
|
|
4
4
|
import {
|
|
5
5
|
MerkleRewardMap, MerklOpportunity, OpportunityAction, OpportunityStatus,
|
|
@@ -30,12 +30,17 @@ export const formatAaveAsset = (_symbol: string) => {
|
|
|
30
30
|
return _symbol;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Live Merkl reward campaigns for Aave V3 on the chain, keyed by aToken. With `asOfTimestamp` (unix
|
|
35
|
+
* seconds) the campaigns and APRs are the ones Merkl had at that moment instead.
|
|
36
|
+
*/
|
|
37
|
+
export const getMerkleCampaigns = async (chainId: NetworkNumber, asOfTimestamp?: number): Promise<MerkleRewardMap> => {
|
|
34
38
|
try {
|
|
35
|
-
const opportunities = await
|
|
39
|
+
const opportunities = await fetchMerklOpportunities({
|
|
36
40
|
mainProtocolId: 'aave',
|
|
41
|
+
chainId: chainId.toString(),
|
|
37
42
|
status: OpportunityStatus.LIVE,
|
|
38
|
-
});
|
|
43
|
+
}, asOfTimestamp);
|
|
39
44
|
const relevantOpportunities = opportunities
|
|
40
45
|
.filter((o: MerklOpportunity) => o.chainId === chainId)
|
|
41
46
|
.filter((o: MerklOpportunity) => o.status === OpportunityStatus.LIVE);
|
package/src/aaveV4/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Client } from 'viem';
|
|
2
2
|
import Dec from 'decimal.js';
|
|
3
3
|
import { assetAmountInEth, assetAmountInWei, getAssetInfoByAddress } from '@defisaver/tokens';
|
|
4
|
-
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
4
|
+
import { getBlockTimestamp, getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
5
5
|
import {
|
|
6
6
|
AaveV4AccountData,
|
|
7
7
|
AaveV4HubAssetOnChainData,
|
|
@@ -32,8 +32,8 @@ import { attachAaveV4MerklIncentives, getAaveV4MerkleCampaigns } from './merkl';
|
|
|
32
32
|
export * as lend from './lend';
|
|
33
33
|
export { getAaveV4MerkleCampaigns } from './merkl';
|
|
34
34
|
|
|
35
|
-
const fetchHubData = async (viewContract: ReturnType<typeof AaveV4ViewContractViem>, hubAddress: EthAddress): Promise<AaveV4HubOnChainData> => {
|
|
36
|
-
const hubData = await viewContract.read.getHubAllAssetsData([hubAddress]);
|
|
35
|
+
const fetchHubData = async (viewContract: ReturnType<typeof AaveV4ViewContractViem>, hubAddress: EthAddress, blockNumber: Blockish = 'latest'): Promise<AaveV4HubOnChainData> => {
|
|
36
|
+
const hubData = await viewContract.read.getHubAllAssetsData([hubAddress], setViemBlockNumber(blockNumber));
|
|
37
37
|
return {
|
|
38
38
|
assets: hubData.reduce((acc: Record<number, AaveV4HubAssetOnChainData>, assetOnChainData) => {
|
|
39
39
|
acc[assetOnChainData.assetId] = {
|
|
@@ -162,19 +162,22 @@ const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAs
|
|
|
162
162
|
});
|
|
163
163
|
};
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
/** `blockTimestamp` (unix seconds) is the historical block's timestamp when already known; otherwise it is read from the block. */
|
|
166
|
+
export async function _getAaveV4SpokeData(provider: Client, network: NetworkNumber, market: AaveV4SpokeInfo, blockNumber: 'latest' | number = 'latest', blockTimestamp?: number): Promise<AaveV4SpokeData> {
|
|
166
167
|
const viewContract = AaveV4ViewContractViem(provider, network, blockNumber);
|
|
167
168
|
|
|
168
169
|
const hubsData: Record<string, AaveV4HubOnChainData> = {};
|
|
169
170
|
const loadHubData = async (hubAddress: EthAddress) => {
|
|
170
|
-
hubsData[hubAddress.toLowerCase()] = await fetchHubData(viewContract, hubAddress);
|
|
171
|
+
hubsData[hubAddress.toLowerCase()] = await fetchHubData(viewContract, hubAddress, blockNumber);
|
|
171
172
|
};
|
|
172
173
|
|
|
173
174
|
// market.hubs is only a prefetch hint (lets known hubs load in parallel with the spoke data), so
|
|
174
175
|
// failures are tolerated here — any hub the reserves actually reference is (re)fetched below.
|
|
175
176
|
const [spokeData, merklCampaigns] = await Promise.all([
|
|
176
|
-
viewContract.read.getSpokeDataFull([market.address]),
|
|
177
|
-
|
|
177
|
+
viewContract.read.getSpokeDataFull([market.address], setViemBlockNumber(blockNumber)),
|
|
178
|
+
// Merkl rewards are keyed by time: a historical block resolves to its timestamp first (one RPC
|
|
179
|
+
// call unless given, none for 'latest') so the rewards in force at that moment are attached.
|
|
180
|
+
getBlockTimestamp(provider, blockNumber, blockTimestamp).then((asOfTimestamp) => getAaveV4MerkleCampaigns(network, asOfTimestamp)),
|
|
178
181
|
...market.hubs.map((hubAddress) => loadHubData(hubAddress).catch(() => {})),
|
|
179
182
|
]);
|
|
180
183
|
|
|
@@ -205,14 +208,14 @@ export async function _getAaveV4SpokeData(provider: Client, network: NetworkNumb
|
|
|
205
208
|
};
|
|
206
209
|
}
|
|
207
210
|
|
|
208
|
-
export async function getAaveV4SpokeData(provider: EthereumProvider, network: NetworkNumber, spoke: AaveV4SpokeInfo, blockNumber: 'latest' | number = 'latest'): Promise<AaveV4SpokeData> {
|
|
209
|
-
return _getAaveV4SpokeData(getViemProvider(provider, network), network, spoke, blockNumber);
|
|
211
|
+
export async function getAaveV4SpokeData(provider: EthereumProvider, network: NetworkNumber, spoke: AaveV4SpokeInfo, blockNumber: 'latest' | number = 'latest', blockTimestamp?: number): Promise<AaveV4SpokeData> {
|
|
212
|
+
return _getAaveV4SpokeData(getViemProvider(provider, network), network, spoke, blockNumber, blockTimestamp);
|
|
210
213
|
}
|
|
211
214
|
|
|
212
215
|
export async function _getAaveV4AccountData(provider: Client, network: NetworkNumber, spokeData: AaveV4SpokeData, address: EthAddress, blockNumber: 'latest' | number = 'latest'): Promise<AaveV4AccountData> {
|
|
213
216
|
const viewContract = AaveV4ViewContractViem(provider, network, blockNumber);
|
|
214
217
|
|
|
215
|
-
const loanData = await viewContract.read.getLoanData([spokeData.address, address]);
|
|
218
|
+
const loanData = await viewContract.read.getLoanData([spokeData.address, address], setViemBlockNumber(blockNumber));
|
|
216
219
|
|
|
217
220
|
const healthFactorFromContract = new Dec(loanData.healthFactor.toString());
|
|
218
221
|
const healthFactor = isMaxUint(healthFactorFromContract.toString()) ? 'Infinity' : healthFactorFromContract.div(1e18).toString();
|
|
@@ -297,7 +300,7 @@ export const _getAaveV4AccountHasAnyBalance = async (
|
|
|
297
300
|
const blockNumber = block === 'latest' ? 'latest' : Number(block);
|
|
298
301
|
const viewContract = AaveV4ViewContractViem(provider, network, blockNumber);
|
|
299
302
|
|
|
300
|
-
const loanData = await viewContract.read.getLoanData([spokeAddress, address]);
|
|
303
|
+
const loanData = await viewContract.read.getLoanData([spokeAddress, address], setViemBlockNumber(blockNumber));
|
|
301
304
|
const reserves = loanData?.reserves || [];
|
|
302
305
|
|
|
303
306
|
return reserves.some((reserveAsset) => {
|
|
@@ -379,14 +382,14 @@ export const getAaveV4AccountBalances = async (
|
|
|
379
382
|
spokeData,
|
|
380
383
|
);
|
|
381
384
|
|
|
382
|
-
const _getAaveV4UnderlyingFromReserveId = async (provider: Client, network: NetworkNumber, spoke: EthAddress, reserveId: number): Promise<any> => {
|
|
383
|
-
const viewContract = AaveV4ViewContractViem(provider, network);
|
|
385
|
+
const _getAaveV4UnderlyingFromReserveId = async (provider: Client, network: NetworkNumber, spoke: EthAddress, reserveId: number, blockNumber: Blockish = 'latest'): Promise<any> => {
|
|
386
|
+
const viewContract = AaveV4ViewContractViem(provider, network, blockNumber);
|
|
384
387
|
|
|
385
|
-
const reserveData = await viewContract.read.getReserveData([spoke, BigInt(reserveId)]);
|
|
388
|
+
const reserveData = await viewContract.read.getReserveData([spoke, BigInt(reserveId)], setViemBlockNumber(blockNumber));
|
|
386
389
|
|
|
387
390
|
return reserveData.underlying;
|
|
388
391
|
};
|
|
389
392
|
|
|
390
|
-
export async function getAaveV4UnderlyingFromReserveId(provider: EthereumProvider, network: NetworkNumber, spoke: EthAddress, reserveId: number): Promise<any> {
|
|
391
|
-
return _getAaveV4UnderlyingFromReserveId(getViemProvider(provider, network), network, spoke, reserveId);
|
|
393
|
+
export async function getAaveV4UnderlyingFromReserveId(provider: EthereumProvider, network: NetworkNumber, spoke: EthAddress, reserveId: number, blockNumber: Blockish = 'latest'): Promise<any> {
|
|
394
|
+
return _getAaveV4UnderlyingFromReserveId(getViemProvider(provider, network), network, spoke, reserveId, blockNumber);
|
|
392
395
|
}
|
package/src/aaveV4/merkl.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Dec from 'decimal.js';
|
|
2
2
|
import { aprToApy } from '../moneymarket';
|
|
3
|
-
import {
|
|
3
|
+
import { fetchMerklOpportunities } from '../services/merkl';
|
|
4
4
|
import {
|
|
5
5
|
AaveV4MerklRewardMap,
|
|
6
6
|
AaveV4MerklIncentive,
|
|
@@ -46,7 +46,11 @@ const buildIncentive = (opportunity: MerklOpportunity): IncentiveData => {
|
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
/**
|
|
50
|
+
* `asOfTimestamp` (unix seconds, defaults to now) decides which of an opportunity's campaigns count
|
|
51
|
+
* as running, so historical opportunity lists are judged at their own moment rather than today's.
|
|
52
|
+
*/
|
|
53
|
+
export const buildAaveV4MerklRewardMap = (opportunities: MerklOpportunity[], chainId: NetworkNumber, asOfTimestamp: number = Date.now() / 1000): AaveV4MerklRewardMap => {
|
|
50
54
|
const result: AaveV4MerklRewardMap = { hub: {}, spoke: {} };
|
|
51
55
|
|
|
52
56
|
const endByCampaignId: Record<string, number> = {};
|
|
@@ -64,7 +68,7 @@ export const buildAaveV4MerklRewardMap = (opportunities: MerklOpportunity[], cha
|
|
|
64
68
|
.filter((o) => typeof o.type === 'string' && o.type.startsWith('AAVE_V4_'))
|
|
65
69
|
.forEach((o) => {
|
|
66
70
|
const side = o.action === OpportunityAction.BORROW ? IncentiveSide.Borrow : IncentiveSide.Supply;
|
|
67
|
-
const now =
|
|
71
|
+
const now = asOfTimestamp;
|
|
68
72
|
const methods = o.campaigns
|
|
69
73
|
?.filter((c) => (c.startTimestamp === undefined || c.startTimestamp <= now)
|
|
70
74
|
&& (c.endTimestamp === undefined || c.endTimestamp > now))
|
|
@@ -136,15 +140,20 @@ export const buildAaveV4MerklRewardMap = (opportunities: MerklOpportunity[], cha
|
|
|
136
140
|
return result;
|
|
137
141
|
};
|
|
138
142
|
|
|
139
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Live Aave V4 Merkl reward campaigns for the chain, split by hub/spoke scope. With `asOfTimestamp`
|
|
145
|
+
* (unix seconds) the campaigns and APRs are the ones Merkl had at that moment instead.
|
|
146
|
+
*/
|
|
147
|
+
export const getAaveV4MerkleCampaigns = async (chainId: NetworkNumber, asOfTimestamp?: number): Promise<AaveV4MerklRewardMap> => {
|
|
140
148
|
try {
|
|
141
|
-
const opportunities = await
|
|
149
|
+
const opportunities = await fetchMerklOpportunities({
|
|
142
150
|
mainProtocolId: 'aave',
|
|
151
|
+
chainId: chainId.toString(),
|
|
143
152
|
type: 'AAVE_V4_HUB_SUPPLY,AAVE_V4_HUB_BORROW,AAVE_V4_SPOKE_SUPPLY,AAVE_V4_SPOKE_BORROW,AAVE_V4_HUB_NET_LENDING,AAVE_V4_HUB_NET_BORROWING,AAVE_V4_SPOKE_NET_LENDING,AAVE_V4_SPOKE_NET_BORROWING',
|
|
144
153
|
status: OpportunityStatus.LIVE,
|
|
145
154
|
campaigns: 'true',
|
|
146
|
-
});
|
|
147
|
-
return buildAaveV4MerklRewardMap(opportunities, chainId);
|
|
155
|
+
}, asOfTimestamp);
|
|
156
|
+
return buildAaveV4MerklRewardMap(opportunities, chainId, asOfTimestamp);
|
|
148
157
|
} catch (e) {
|
|
149
158
|
console.error('Failed to fetch Aave V4 Merkle campaigns', e);
|
|
150
159
|
return { hub: {}, spoke: {} };
|
package/src/claiming/aaveV3.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Client } from 'viem';
|
|
2
2
|
import Dec from 'decimal.js';
|
|
3
|
-
import { EthAddress, NetworkNumber } from '../types';
|
|
3
|
+
import { Blockish, EthAddress, NetworkNumber } from '../types';
|
|
4
4
|
import { ClaimableToken, ClaimType, MerklRewardsClaimableToken } from '../types/claiming';
|
|
5
5
|
import {
|
|
6
6
|
AaveIncentiveDataProviderV3ContractViem,
|
|
7
7
|
AaveRewardsControllerViem,
|
|
8
8
|
} from '../contracts';
|
|
9
9
|
import { compareAddresses, getEthAmountForDecimals, LONGER_TIMEOUT } from '../services/utils';
|
|
10
|
+
import { setViemBlockNumber } from '../services/viem';
|
|
10
11
|
import { getAaveUnderlyingSymbol } from '../helpers/aaveHelpers';
|
|
11
12
|
|
|
12
13
|
type AaveReward = {
|
|
@@ -37,9 +38,10 @@ export async function getUnclaimedRewardsForAllMarkets(
|
|
|
37
38
|
network: NetworkNumber,
|
|
38
39
|
walletAddress: EthAddress,
|
|
39
40
|
marketAddress: EthAddress,
|
|
41
|
+
blockNumber: Blockish = 'latest',
|
|
40
42
|
): Promise<ClaimableToken[]> {
|
|
41
43
|
const contract = AaveIncentiveDataProviderV3ContractViem(provider, network);
|
|
42
|
-
const tokensData = await contract.read.getUserReservesIncentivesData([marketAddress, walletAddress]);
|
|
44
|
+
const tokensData = await contract.read.getUserReservesIncentivesData([marketAddress, walletAddress], setViemBlockNumber(blockNumber));
|
|
43
45
|
const allTokensDataArrays = tokensData.reduce((acc: any[], val) => {
|
|
44
46
|
acc.push(val.aTokenIncentivesUserData.userRewardsInformation);
|
|
45
47
|
acc.push(val.vTokenIncentivesUserData.userRewardsInformation);
|
|
@@ -54,7 +56,7 @@ export async function getUnclaimedRewardsForAllMarkets(
|
|
|
54
56
|
// reward can be any token like wstETH, but also aToken like aWETH
|
|
55
57
|
const aaveRewardsController = AaveRewardsControllerViem(provider, network);
|
|
56
58
|
const rewardsPerAAsset = await Promise.all(allATokens.map(
|
|
57
|
-
(token: string) => aaveRewardsController.read.getAllUserRewards([[token as EthAddress], walletAddress])));
|
|
59
|
+
(token: string) => aaveRewardsController.read.getAllUserRewards([[token as EthAddress], walletAddress], setViemBlockNumber(blockNumber))));
|
|
58
60
|
|
|
59
61
|
// match amounts to token symbol, parse decimal amounts
|
|
60
62
|
const rewardsPerAAssetWithInfo = rewardsPerAAsset.map((rewardForAAsset, aaIndex) => {
|
package/src/claiming/king.ts
CHANGED
|
@@ -2,7 +2,10 @@ import Dec from 'decimal.js';
|
|
|
2
2
|
import { assetAmountInEth } from '@defisaver/tokens';
|
|
3
3
|
import { Client } from 'viem';
|
|
4
4
|
import { UUPSViem } from '../contracts';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Blockish, EthAddress, HexString, NetworkNumber,
|
|
7
|
+
} from '../types/common';
|
|
8
|
+
import { setViemBlockNumber } from '../services/viem';
|
|
6
9
|
import { ClaimType } from '../types/claiming';
|
|
7
10
|
|
|
8
11
|
export const fetchKingRewards = async (walletAddress: EthAddress) => {
|
|
@@ -19,14 +22,14 @@ export const fetchKingRewards = async (walletAddress: EthAddress) => {
|
|
|
19
22
|
}
|
|
20
23
|
};
|
|
21
24
|
|
|
22
|
-
export const getKingRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[]) => {
|
|
25
|
+
export const getKingRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[], blockNumber: Blockish = 'latest') => {
|
|
23
26
|
// Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
|
|
24
27
|
const apiDataPromises = walletAddresses.map(address => fetchKingRewards(address));
|
|
25
28
|
const apiDataArray = await Promise.all(apiDataPromises);
|
|
26
29
|
|
|
27
30
|
// Batch all contract calls using multicall
|
|
28
31
|
const contract = UUPSViem(provider, network);
|
|
29
|
-
const cumulativePromises = walletAddresses.map(address => contract.read.cumulativeClaimed([address]),
|
|
32
|
+
const cumulativePromises = walletAddresses.map(address => contract.read.cumulativeClaimed([address], setViemBlockNumber(blockNumber)),
|
|
30
33
|
);
|
|
31
34
|
const cumulativeResults = await Promise.all(cumulativePromises);
|
|
32
35
|
|
package/src/claiming/spark.ts
CHANGED
|
@@ -6,9 +6,10 @@ import {
|
|
|
6
6
|
SparkIncentiveDataProviderContractViem,
|
|
7
7
|
SparkRewardsControllerViem,
|
|
8
8
|
} from '../contracts';
|
|
9
|
-
import { EthAddress, NetworkNumber } from '../types/common';
|
|
9
|
+
import { Blockish, EthAddress, NetworkNumber } from '../types/common';
|
|
10
10
|
import { ClaimType, SparkAirdropType, SparkRewardsClaimableToken } from '../types/claiming';
|
|
11
11
|
import { compareAddresses, getEthAmountForDecimals } from '../services/utils';
|
|
12
|
+
import { setViemBlockNumber } from '../services/viem';
|
|
12
13
|
|
|
13
14
|
const IGNITION_REWARDS = '0xCBA0C0a2a0B6Bb11233ec4EA85C5bFfea33e724d';
|
|
14
15
|
const PFL3_REWARDS = '0x7ac96180C4d6b2A328D3a19ac059D0E7Fc3C6d41';
|
|
@@ -31,7 +32,7 @@ type CumulativeClaimedSpkAirdropFuncProp = {
|
|
|
31
32
|
user: string, tokenAddress: string, epoch: number, type: SparkAirdropType,
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
const getCumulativeClaimedSpkAirdrop = async (provider: Client, network: NetworkNumber, data: CumulativeClaimedSpkAirdropFuncProp[]) => {
|
|
35
|
+
const getCumulativeClaimedSpkAirdrop = async (provider: Client, network: NetworkNumber, data: CumulativeClaimedSpkAirdropFuncProp[], blockNumber: Blockish = 'latest') => {
|
|
35
36
|
const contractIgnition = createViemContractFromConfigFunc('SparkAirdrop', IGNITION_REWARDS)(provider, network);
|
|
36
37
|
const contractPFL = createViemContractFromConfigFunc('SparkAirdrop', PFL3_REWARDS)(provider, network);
|
|
37
38
|
|
|
@@ -40,7 +41,7 @@ const getCumulativeClaimedSpkAirdrop = async (provider: Client, network: Network
|
|
|
40
41
|
user, tokenAddress, epoch, type,
|
|
41
42
|
} = airdrop;
|
|
42
43
|
const contract = type === SparkAirdropType.SPARK_IGNITION ? contractIgnition : contractPFL;
|
|
43
|
-
return contract.read.cumulativeClaimed([user as EthAddress, tokenAddress as EthAddress, BigInt(epoch)]);
|
|
44
|
+
return contract.read.cumulativeClaimed([user as EthAddress, tokenAddress as EthAddress, BigInt(epoch)], setViemBlockNumber(blockNumber));
|
|
44
45
|
}));
|
|
45
46
|
|
|
46
47
|
return cumulativeAmounts.map((amount: bigint, i: number) => assetAmountInEth(amount.toString(), getAssetInfoByAddress(data[i].tokenAddress).symbol).toString());
|
|
@@ -50,6 +51,7 @@ export const fetchSparkAirdropRewards = async (
|
|
|
50
51
|
provider: Client,
|
|
51
52
|
network: NetworkNumber,
|
|
52
53
|
walletAddresses: EthAddress[],
|
|
54
|
+
blockNumber: Blockish = 'latest',
|
|
53
55
|
) => {
|
|
54
56
|
// Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
|
|
55
57
|
const apiDataPromises = walletAddresses.map(address => fetchSpkAirdropRewards(address));
|
|
@@ -89,7 +91,7 @@ export const fetchSparkAirdropRewards = async (
|
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
// Batch all contract calls
|
|
92
|
-
const cumulativeClaimedAmounts = await getCumulativeClaimedSpkAirdrop(provider, network, contractCallsData);
|
|
94
|
+
const cumulativeClaimedAmounts = await getCumulativeClaimedSpkAirdrop(provider, network, contractCallsData, blockNumber);
|
|
93
95
|
|
|
94
96
|
// Process results
|
|
95
97
|
const results: Record<string, any[]> = {};
|
|
@@ -142,9 +144,10 @@ export const fetchSparkRewards = async (
|
|
|
142
144
|
network: NetworkNumber,
|
|
143
145
|
walletAddress: EthAddress,
|
|
144
146
|
marketAddress: EthAddress,
|
|
147
|
+
blockNumber: Blockish = 'latest',
|
|
145
148
|
): Promise<SparkRewardsClaimableToken[]> => {
|
|
146
149
|
const contract = SparkIncentiveDataProviderContractViem(provider, network);
|
|
147
|
-
const tokensData = await contract.read.getUserReservesIncentivesData([marketAddress, walletAddress]);
|
|
150
|
+
const tokensData = await contract.read.getUserReservesIncentivesData([marketAddress, walletAddress], setViemBlockNumber(blockNumber));
|
|
148
151
|
const allTokensDataArrays = tokensData.reduce((acc: any[], val) => {
|
|
149
152
|
acc.push(val.aTokenIncentivesUserData.userRewardsInformation);
|
|
150
153
|
acc.push(val.vTokenIncentivesUserData.userRewardsInformation);
|
|
@@ -165,7 +168,7 @@ export const fetchSparkRewards = async (
|
|
|
165
168
|
};
|
|
166
169
|
const rewardsPerAAsset = await Promise.all(allATokens.map((token: EthAddress) => {
|
|
167
170
|
const sparkRewardsContract = SparkRewardsControllerViem(provider, network);
|
|
168
|
-
return sparkRewardsContract.read.getAllUserRewards([[token], walletAddress]);
|
|
171
|
+
return sparkRewardsContract.read.getAllUserRewards([[token], walletAddress], setViemBlockNumber(blockNumber));
|
|
169
172
|
}));
|
|
170
173
|
|
|
171
174
|
// match amounts to token symbol, parse decimal amounts
|
package/src/claiming/uniswap.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Dec from 'decimal.js';
|
|
2
2
|
import { Client } from 'viem';
|
|
3
3
|
import { assetAmountInEth } from '@defisaver/tokens';
|
|
4
|
-
import { EthAddress, NetworkNumber } from '../types';
|
|
4
|
+
import { Blockish, EthAddress, NetworkNumber } from '../types';
|
|
5
|
+
import { setViemBlockNumber } from '../services/viem';
|
|
5
6
|
import { UniswapTokenDistributorViem } from '../contracts';
|
|
6
7
|
import { ClaimType, UniswapAirdropClaimableToken } from '../types/claiming';
|
|
7
8
|
|
|
@@ -25,14 +26,14 @@ export const fetchUniswapRewardsData = async (walletAddress: EthAddress) => {
|
|
|
25
26
|
}
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
export const getUniswapRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[]): Promise<Record<string, UniswapAirdropClaimableToken[]>> => {
|
|
29
|
+
export const getUniswapRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[], blockNumber: Blockish = 'latest'): Promise<Record<string, UniswapAirdropClaimableToken[]>> => {
|
|
29
30
|
// Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
|
|
30
31
|
const apiDataPromises = walletAddresses.map(address => fetchUniswapRewardsData(address));
|
|
31
32
|
const apiDataArray = await Promise.all(apiDataPromises);
|
|
32
33
|
|
|
33
34
|
// Batch all contract calls using multicall
|
|
34
35
|
const contract = UniswapTokenDistributorViem(provider, network);
|
|
35
|
-
const cumulativePromises = apiDataArray.map(data => (data.index ? contract.read.isClaimed([data.index]) : Promise.resolve(false)),
|
|
36
|
+
const cumulativePromises = apiDataArray.map(data => (data.index ? contract.read.isClaimed([data.index], setViemBlockNumber(blockNumber)) : Promise.resolve(false)),
|
|
36
37
|
);
|
|
37
38
|
const cumulativeResults = await Promise.all(cumulativePromises);
|
|
38
39
|
|
package/src/compoundV2/index.ts
CHANGED
|
@@ -17,11 +17,11 @@ import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
|
17
17
|
|
|
18
18
|
const compAddress = '0xc00e94cb662c3520282e6f5717214004a7f26888';
|
|
19
19
|
|
|
20
|
-
export const _getCompoundV2MarketsData = async (provider: Client, network: NetworkNumber): Promise<CompoundV2MarketsData> => {
|
|
20
|
+
export const _getCompoundV2MarketsData = async (provider: Client, network: NetworkNumber, blockNumber: Blockish = 'latest'): Promise<CompoundV2MarketsData> => {
|
|
21
21
|
const cAddresses = compoundV2CollateralAssets.map(a => a.address);
|
|
22
22
|
|
|
23
23
|
const loanInfoContract = CompoundLoanInfoContractViem(provider, network);
|
|
24
|
-
const loanInfo = await loanInfoContract.read.getFullTokensInfo([cAddresses as EthAddress[]]);
|
|
24
|
+
const loanInfo = await loanInfoContract.read.getFullTokensInfo([cAddresses as EthAddress[]], setViemBlockNumber(blockNumber));
|
|
25
25
|
|
|
26
26
|
const compPrice = loanInfo.find(m => compareAddresses(m.underlyingTokenAddress, compAddress))!.price.toString();
|
|
27
27
|
|
|
@@ -86,7 +86,7 @@ export const _getCompoundV2MarketsData = async (provider: Client, network: Netwo
|
|
|
86
86
|
return { assetsData: payload };
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
export const getCompoundV2MarketsData = async (provider: EthereumProvider, network: NetworkNumber): Promise<CompoundV2MarketsData> => _getCompoundV2MarketsData(getViemProvider(provider, network), network);
|
|
89
|
+
export const getCompoundV2MarketsData = async (provider: EthereumProvider, network: NetworkNumber, blockNumber: Blockish = 'latest'): Promise<CompoundV2MarketsData> => _getCompoundV2MarketsData(getViemProvider(provider, network), network, blockNumber);
|
|
90
90
|
|
|
91
91
|
export const EMPTY_COMPOUND_DATA = {
|
|
92
92
|
usedAssets: {},
|
|
@@ -103,10 +103,10 @@ export const EMPTY_COMPOUND_DATA = {
|
|
|
103
103
|
exposure: 'N/A',
|
|
104
104
|
};
|
|
105
105
|
|
|
106
|
-
const getCollateralAssetsAddresses = async (provider: Client, network: NetworkNumber, account: EthAddress) => {
|
|
106
|
+
const getCollateralAssetsAddresses = async (provider: Client, network: NetworkNumber, account: EthAddress, blockNumber: Blockish = 'latest') => {
|
|
107
107
|
const contract = ComptrollerContractViem(provider, network);
|
|
108
108
|
|
|
109
|
-
return contract.read.getAssetsIn([account]);
|
|
109
|
+
return contract.read.getAssetsIn([account], setViemBlockNumber(blockNumber));
|
|
110
110
|
};
|
|
111
111
|
|
|
112
112
|
const getAllMarketAddresses = async (provider: Client, network: NetworkNumber, block: Blockish) => {
|
|
@@ -172,15 +172,15 @@ export const getCompoundV2AccountBalances = async (
|
|
|
172
172
|
address: EthAddress,
|
|
173
173
|
): Promise<PositionBalances> => _getCompoundV2AccountBalances(getViemProvider(provider, network), network, block, addressMapping, address);
|
|
174
174
|
|
|
175
|
-
export const _getCompoundV2AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, assetsData: CompoundV2AssetsData): Promise<CompoundV2PositionData> => {
|
|
175
|
+
export const _getCompoundV2AccountData = async (provider: Client, network: NetworkNumber, address: EthAddress, assetsData: CompoundV2AssetsData, blockNumber: Blockish = 'latest'): Promise<CompoundV2PositionData> => {
|
|
176
176
|
if (!address) throw new Error('No address provided');
|
|
177
177
|
|
|
178
178
|
let payload = { ...EMPTY_COMPOUND_DATA, lastUpdated: Date.now() };
|
|
179
179
|
|
|
180
180
|
const loanInfoContract = CompoundLoanInfoContractViem(provider, network);
|
|
181
181
|
const [loanInfo, collateralAssetsAddresses] = await Promise.all([
|
|
182
|
-
loanInfoContract.read.getTokenBalances([address, compoundV2CollateralAssets.map(a => a.address) as EthAddress[]]),
|
|
183
|
-
getCollateralAssetsAddresses(provider, network, address),
|
|
182
|
+
loanInfoContract.read.getTokenBalances([address, compoundV2CollateralAssets.map(a => a.address) as EthAddress[]], setViemBlockNumber(blockNumber)),
|
|
183
|
+
getCollateralAssetsAddresses(provider, network, address, blockNumber),
|
|
184
184
|
]);
|
|
185
185
|
|
|
186
186
|
const usedAssets = {} as CompoundV2UsedAssets;
|
|
@@ -236,7 +236,8 @@ export const getCompoundV2AccountData = async (
|
|
|
236
236
|
network: NetworkNumber,
|
|
237
237
|
address: EthAddress,
|
|
238
238
|
assetsData: CompoundV2AssetsData,
|
|
239
|
-
|
|
239
|
+
blockNumber: Blockish = 'latest',
|
|
240
|
+
): Promise<CompoundV2PositionData> => _getCompoundV2AccountData(getViemProvider(provider, network), network, address, assetsData, blockNumber);
|
|
240
241
|
|
|
241
242
|
export const getCompoundV2FullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress): Promise<CompoundV2PositionData> => {
|
|
242
243
|
const marketData = await getCompoundV2MarketsData(provider, network);
|
package/src/compoundV3/index.ts
CHANGED
|
@@ -23,17 +23,18 @@ import { CompoundMarkets } from '../markets/compound';
|
|
|
23
23
|
import {
|
|
24
24
|
getEthPrice, getCompPrice, getUSDCPrice, getWstETHPrice,
|
|
25
25
|
} from '../services/priceService';
|
|
26
|
-
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
26
|
+
import { getBlockTimestamp, getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
27
27
|
import { attachCompoundV3MerklIncentives, getCompoundV3MerklOpportunities } from './merkl';
|
|
28
28
|
|
|
29
29
|
export { getCompoundV3MerklOpportunities, attachCompoundV3MerklIncentives } from './merkl';
|
|
30
30
|
|
|
31
31
|
const getSupportedAssetsAddressesForMarket = (selectedMarket: CompoundMarketData, network: NetworkNumber) => selectedMarket.collAssets.map(asset => getAssetInfo(ethToWeth(asset), network)).map(addr => addr.address.toLowerCase());
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
// Every branch takes (client, block) so the caller can pin the price read to the market block.
|
|
34
|
+
const getBaseAssetPriceFunction = (asset: string): ((client: Client, block: Blockish) => Promise<string>) => {
|
|
34
35
|
switch (asset) {
|
|
35
36
|
case 'wstETH':
|
|
36
|
-
return getWstETHPrice;
|
|
37
|
+
return (client, block) => getWstETHPrice(client, NetworkNumber.Eth, block);
|
|
37
38
|
case 'ETH':
|
|
38
39
|
return getEthPrice;
|
|
39
40
|
default:
|
|
@@ -41,16 +42,19 @@ const getBaseAssetPriceFunction = (asset: string) => {
|
|
|
41
42
|
}
|
|
42
43
|
};
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
/** `blockTimestamp` (unix seconds) is the historical block's timestamp when already known; otherwise it is read from the block. */
|
|
46
|
+
export const _getCompoundV3MarketsData = async (provider: Client, network: NetworkNumber, selectedMarket: CompoundMarketData, defaultProvider: Client, blockNumber: Blockish = 'latest', blockTimestamp?: number): Promise<CompoundV3MarketsData> => {
|
|
45
47
|
const contract = CompV3ViewContractViem(provider, network);
|
|
46
48
|
|
|
47
49
|
const [baseAssetPrice, compPrice, baseTokenInfo, collInfos, govInfo, merklOpportunities] = await Promise.all([
|
|
48
|
-
getBaseAssetPriceFunction(selectedMarket.baseAsset)(defaultProvider),
|
|
49
|
-
getCompPrice(defaultProvider),
|
|
50
|
-
contract.read.getFullBaseTokenInfo([selectedMarket.baseMarketAddress]),
|
|
51
|
-
contract.read.getFullCollInfos([selectedMarket.baseMarketAddress]),
|
|
52
|
-
contract.read.getGovernanceInfoFull([selectedMarket.baseMarketAddress]),
|
|
53
|
-
|
|
50
|
+
getBaseAssetPriceFunction(selectedMarket.baseAsset)(defaultProvider, blockNumber),
|
|
51
|
+
getCompPrice(defaultProvider, blockNumber),
|
|
52
|
+
contract.read.getFullBaseTokenInfo([selectedMarket.baseMarketAddress], setViemBlockNumber(blockNumber)),
|
|
53
|
+
contract.read.getFullCollInfos([selectedMarket.baseMarketAddress], setViemBlockNumber(blockNumber)),
|
|
54
|
+
contract.read.getGovernanceInfoFull([selectedMarket.baseMarketAddress], setViemBlockNumber(blockNumber)),
|
|
55
|
+
// Merkl rewards are keyed by time: a historical block resolves to its timestamp first (one RPC
|
|
56
|
+
// call unless given, none for 'latest') so the rewards in force at that moment are attached.
|
|
57
|
+
getBlockTimestamp(provider, blockNumber, blockTimestamp).then((asOfTimestamp) => getCompoundV3MerklOpportunities(asOfTimestamp, network)),
|
|
54
58
|
]);
|
|
55
59
|
|
|
56
60
|
const { isSupplyPaused, isWithdrawPaused } = govInfo;
|
|
@@ -95,7 +99,7 @@ export const _getCompoundV3MarketsData = async (provider: Client, network: Netwo
|
|
|
95
99
|
};
|
|
96
100
|
};
|
|
97
101
|
|
|
98
|
-
export const getCompoundV3MarketsData = async (provider: EthereumProvider, network: NetworkNumber, selectedMarket: CompoundMarketData, defaultProvider: EthereumProvider): Promise<CompoundV3MarketsData> => _getCompoundV3MarketsData(getViemProvider(provider, network), network, selectedMarket, getViemProvider(defaultProvider, network));
|
|
102
|
+
export const getCompoundV3MarketsData = async (provider: EthereumProvider, network: NetworkNumber, selectedMarket: CompoundMarketData, defaultProvider: EthereumProvider, blockNumber: Blockish = 'latest', blockTimestamp?: number): Promise<CompoundV3MarketsData> => _getCompoundV3MarketsData(getViemProvider(provider, network), network, selectedMarket, getViemProvider(defaultProvider, network), blockNumber, blockTimestamp);
|
|
99
103
|
|
|
100
104
|
export const EMPTY_COMPOUND_V3_DATA = {
|
|
101
105
|
usedAssets: {},
|
|
@@ -183,6 +187,7 @@ export const _getCompoundV3AccountData = async (
|
|
|
183
187
|
selectedMarket: CompoundMarketData,
|
|
184
188
|
assetsData: CompoundV3AssetsData,
|
|
185
189
|
}),
|
|
190
|
+
blockNumber: Blockish = 'latest',
|
|
186
191
|
): Promise<CompoundV3PositionData> => {
|
|
187
192
|
if (!address) throw new Error('No address provided');
|
|
188
193
|
const {
|
|
@@ -198,8 +203,8 @@ export const _getCompoundV3AccountData = async (
|
|
|
198
203
|
|
|
199
204
|
|
|
200
205
|
const [loanData, isAllowed] = await Promise.all([
|
|
201
|
-
contract.read.getLoanData([selectedMarket.baseMarketAddress, address]),
|
|
202
|
-
contract.read.isAllowed([selectedMarket.baseMarketAddress, address, (proxyAddress || ZERO_ADDRESS)]),
|
|
206
|
+
contract.read.getLoanData([selectedMarket.baseMarketAddress, address], setViemBlockNumber(blockNumber)),
|
|
207
|
+
contract.read.isAllowed([selectedMarket.baseMarketAddress, address, (proxyAddress || ZERO_ADDRESS)], setViemBlockNumber(blockNumber)),
|
|
203
208
|
]);
|
|
204
209
|
|
|
205
210
|
const usedAssets: CompoundV3UsedAssets = {};
|
|
@@ -274,7 +279,8 @@ export const getCompoundV3AccountData = async (
|
|
|
274
279
|
selectedMarket: CompoundMarketData,
|
|
275
280
|
assetsData: CompoundV3AssetsData,
|
|
276
281
|
}),
|
|
277
|
-
|
|
282
|
+
blockNumber: Blockish = 'latest',
|
|
283
|
+
): Promise<CompoundV3PositionData> => _getCompoundV3AccountData(getViemProvider(provider, network), network, address, proxyAddress, extractedState, blockNumber);
|
|
278
284
|
|
|
279
285
|
export const getCompoundV3FullPositionData = async (provider: EthereumProvider, network: NetworkNumber, address: EthAddress, proxyAddress: EthAddress, selectedMarket: CompoundMarketData, defaultProvider: EthereumProvider): Promise<CompoundV3PositionData> => {
|
|
280
286
|
const marketData = await getCompoundV3MarketsData(provider, network, selectedMarket, defaultProvider);
|