UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

351 lines 16.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getUserMorphoRewardsData = getUserMorphoRewardsData; exports.getUserMorphoStakingRewardsData = getUserMorphoStakingRewardsData; const lodash_1 = __importDefault(require("lodash")); const { uniq } = lodash_1.default; const viem_1 = require("viem"); const amount_js_1 = require("../../../common/amount.js"); const fetch_headers_js_1 = require("../../../common/fetch-headers.js"); const index_js_1 = require("../../../environments/index.js"); const index_js_2 = require("../../../environments/utils/index.js"); const graphql_js_1 = require("../utils/graphql.js"); async function getUserMorphoRewardsData(params) { const merklRewards = await getMerklRewardsData(params.environment, params.account); if (params.environment.custom.morpho?.minimalDeployment === false) { const morphoRewards = await getMorphoRewardsData(params.environment.chainId, params.account); const morphoAssets = await getMorphoAssetsData(morphoRewards.map((r) => r.asset.address)); const morphoResult = morphoRewards.map((r) => { const asset = morphoAssets.find((a) => a.address.toLowerCase() === r.asset.address.toLowerCase()); if (!asset) { return undefined; } const rewardToken = { address: asset.address, decimals: asset.decimals, symbol: asset.symbol, name: asset.name, }; switch (r.type) { case "uniform-reward": { const claimableNow = new amount_js_1.Amount(BigInt(r.amount?.claimable_now || 0), rewardToken.decimals); const claimableNowUsd = claimableNow.value * (asset.priceUsd || 0); const claimableFuture = new amount_js_1.Amount(BigInt(r.amount?.claimable_next || 0), rewardToken.decimals); const claimableFutureUsd = claimableFuture.value * (asset.priceUsd || 0); const uniformReward = { type: "uniform-reward", chainId: r.asset.chain_id, account: r.user, rewardToken, claimableNow, claimableNowUsd, claimableFuture, claimableFutureUsd, }; return uniformReward; } case "market-reward": { const claimableNow = new amount_js_1.Amount(BigInt(r.for_supply?.claimable_now || 0), rewardToken.decimals); const claimableNowUsd = claimableNow.value * (asset.priceUsd || 0); const claimableFuture = new amount_js_1.Amount(BigInt(r.for_supply?.claimable_next || 0), rewardToken.decimals); const claimableFutureUsd = claimableFuture.value * (asset.priceUsd || 0); const collateralClaimableNow = new amount_js_1.Amount(BigInt(r.for_collateral?.claimable_now || 0), rewardToken.decimals); const collateralClaimableNowUsd = collateralClaimableNow.value * (asset.priceUsd || 0); const collateralClaimableFuture = new amount_js_1.Amount(BigInt(r.for_collateral?.claimable_next || 0), rewardToken.decimals); const collateralClaimableFutureUsd = collateralClaimableFuture.value * (asset.priceUsd || 0); const borrowClaimableNow = new amount_js_1.Amount(BigInt(r.for_borrow?.claimable_now || 0), rewardToken.decimals); const borrowClaimableNowUsd = borrowClaimableNow.value * (asset.priceUsd || 0); const borrowClaimableFuture = new amount_js_1.Amount(BigInt(r.for_borrow?.claimable_next || 0), rewardToken.decimals); const borrowClaimableFutureUsd = borrowClaimableFuture.value * (asset.priceUsd || 0); if (r.reallocated_from) { const vaultReward = { type: "vault-reward", chainId: r.program.chain_id, account: r.user, vaultId: r.reallocated_from, rewardToken, claimableNow, claimableNowUsd, claimableFuture, claimableFutureUsd, }; return vaultReward; } else { const marketReward = { type: "market-reward", chainId: r.program.chain_id, account: r.user, marketId: r.program.market_id || "", rewardToken, collateralRewards: { claimableNow: collateralClaimableNow, claimableNowUsd: collateralClaimableNowUsd, claimableFuture: collateralClaimableFuture, claimableFutureUsd: collateralClaimableFutureUsd, }, borrowRewards: { claimableNow: borrowClaimableNow, claimableNowUsd: borrowClaimableNowUsd, claimableFuture: borrowClaimableFuture, claimableFutureUsd: borrowClaimableFutureUsd, }, }; return marketReward; } } case "vault-reward": { const claimableNow = new amount_js_1.Amount(BigInt(r.for_supply?.claimable_now || 0), rewardToken.decimals); const claimableNowUsd = claimableNow.value * (asset.priceUsd || 0); const claimableFuture = new amount_js_1.Amount(BigInt(r.for_supply?.claimable_next || 0), rewardToken.decimals); const claimableFutureUsd = claimableFuture.value * (asset.priceUsd || 0); const vaultReward = { type: "vault-reward", chainId: r.program.chain_id, account: r.user, vaultId: r.program.vault, rewardToken, claimableNow, claimableNowUsd, claimableFuture, claimableFutureUsd, }; return vaultReward; } } }); const merklResult = []; for (const chainData of merklRewards) { for (const reward of chainData.rewards) { const morphoAsset = morphoAssets.find((a) => a.address.toLowerCase() === reward.token.address.toLowerCase()); const rewardToken = { address: reward.token.address, decimals: morphoAsset?.decimals ?? reward.token.decimals, symbol: morphoAsset?.symbol ?? reward.token.symbol, name: morphoAsset?.name ?? reward.token.symbol, }; const claimableNow = new amount_js_1.Amount(BigInt(reward.amount) - BigInt(reward.claimed), rewardToken.decimals); const claimableNowUsd = claimableNow.value * (morphoAsset?.priceUsd ?? reward.token.price ?? 0); const claimableFuture = new amount_js_1.Amount(BigInt(reward.pending), rewardToken.decimals); const claimableFutureUsd = claimableFuture.value * (morphoAsset?.priceUsd ?? reward.token.price ?? 0); const merklReward = { type: "merkl-reward", chainId: chainData.chain.id, account: params.account, rewardToken, claimableNow, claimableNowUsd, claimableFuture, claimableFutureUsd, }; merklResult.push(merklReward); } } const allResults = [ ...morphoResult.filter((r) => r !== undefined), ...merklResult, ]; return allResults; } const merklResult = []; for (const chainData of merklRewards) { for (const reward of chainData.rewards) { const rewardToken = { address: reward.token.address, decimals: reward.token.decimals, symbol: reward.token.symbol, name: reward.token.symbol, }; const claimableNow = new amount_js_1.Amount(BigInt(reward.amount) - BigInt(reward.claimed), rewardToken.decimals); const claimableNowUsd = claimableNow.value * (reward.token.price ?? 0); const claimableFuture = new amount_js_1.Amount(BigInt(reward.pending), rewardToken.decimals); const claimableFutureUsd = claimableFuture.value * (reward.token.price ?? 0); const merklReward = { type: "merkl-reward", chainId: chainData.chain.id, account: params.account, rewardToken, claimableNow, claimableNowUsd, claimableFuture, claimableFutureUsd, }; merklResult.push(merklReward); } } return merklResult; } async function getUserMorphoStakingRewardsData(params) { const vaultsWithStaking = Object.values(params.environment.config.vaults).filter((vault) => Boolean(vault.multiReward)); if (!vaultsWithStaking.length) { return []; } const rewards = await Promise.all(vaultsWithStaking.map(async (vault) => { if (!vault.multiReward) return []; const vaultRewards = await getRewardsEarnedData(params.environment, params.account, vault.multiReward); const homeEnvironment = Object.values(index_js_1.publicEnvironments).find((e) => e.custom?.governance?.chainIds?.includes(params.environment.chainId)) || params.environment; const viewsContract = params.environment.contracts.views; const homeViewsContract = homeEnvironment.contracts.views; const userData = await Promise.all([ viewsContract?.read.getAllMarketsInfo(), homeViewsContract?.read.getNativeTokenPrice(), homeViewsContract?.read.getGovernanceTokenPrice(), ]); const [allMarkets, nativeTokenPriceRaw, governanceTokenPriceRaw] = userData; const governanceTokenPrice = new amount_js_1.Amount(governanceTokenPriceRaw || 0n, 18); const nativeTokenPrice = new amount_js_1.Amount(nativeTokenPriceRaw || 0n, 18); let tokenPrices = allMarkets ?.map((marketInfo) => { const marketFound = (0, index_js_2.findMarketByAddress)(params.environment, marketInfo.market); if (marketFound) { return { token: marketFound.underlyingToken, tokenPrice: new amount_js_1.Amount(marketInfo.underlyingPrice, 36 - marketFound.underlyingToken.decimals), }; } else { return; } }) .filter((token) => !!token) || []; if (params.environment.custom?.governance?.token) { tokenPrices = [ ...tokenPrices, { token: params.environment.config.tokens[params.environment.custom.governance.token], tokenPrice: governanceTokenPrice, }, ]; } tokenPrices = [ ...tokenPrices, { token: (0, index_js_2.findTokenByAddress)(params.environment, viem_1.zeroAddress), tokenPrice: nativeTokenPrice, }, ]; return vaultRewards .filter((reward) => { return reward !== undefined && reward.amount.value > 0; }) .map((reward) => { const market = tokenPrices.find((m) => m?.token.address === reward.token.address); const priceUsd = market?.tokenPrice.value ?? 0; return { ...reward, chainId: params.environment.chainId, amountUsd: reward.amount.value * priceUsd, }; }); })); return rewards.flat(); } const getRewardsEarnedData = async (environment, userAddress, multiRewardsAddress) => { if (!environment.custom.multiRewarder) { return []; } const multiRewardAbi = (0, viem_1.parseAbi)([ "function earned(address account, address token) view returns (uint256)", ]); const multiRewardContract = (0, viem_1.getContract)({ address: multiRewardsAddress, abi: multiRewardAbi, client: environment.publicClient, }); const rewards = await Promise.all(environment.custom.multiRewarder.map(async (multiRewarder) => { const token = environment.config.tokens[multiRewarder.rewardToken]; if (!token) { return; } try { const earned = await multiRewardContract.read.earned([ userAddress, token.address, ]); return { amount: new amount_js_1.Amount(BigInt(earned), token.decimals), token }; } catch { return { amount: new amount_js_1.Amount(0n, token.decimals), token }; } })); return rewards.filter(Boolean); }; async function getMorphoRewardsData(chainId, account) { const rewardsRequest = await fetch(`https://rewards.morpho.org/v1/users/${account}/rewards?chain_id=${chainId}&trusted=true&exclude_merkl_programs=true`, { headers: fetch_headers_js_1.MOONWELL_FETCH_JSON_HEADERS, }); const rewards = await rewardsRequest.json(); return (rewards.data || []); } async function getMorphoAssetsData(addresses) { const rewardsRequest = await (0, graphql_js_1.getGraphQL)(` query { assets(where: { address_in:[${uniq(addresses) .map((a) => `"${a.toLowerCase()}"`) .join(",")}]}) { items { address symbol priceUsd name decimals } } } `); if (rewardsRequest) { return rewardsRequest.assets.items; } return []; } async function getMerklRewardsData(environment, account) { try { const chainIdsPromises = Object.values(environment.config.vaults).map(async (vault) => { try { const response = await fetch(`https://api.merkl.xyz/v4/opportunities?identifier=${environment.config.tokens[vault.vaultToken]?.address}&chainId=${environment.chainId}&status=LIVE`, { headers: fetch_headers_js_1.MOONWELL_FETCH_JSON_HEADERS, }); if (!response.ok) { console.warn(`Failed to fetch opportunities: ${response.status} ${response.statusText}`); return []; } const data = await response.json(); return data.flatMap((opportunity) => opportunity.rewardsRecord.breakdowns.map((breakdown) => breakdown.token.chainId)); } catch (error) { console.warn(`Error fetching opportunities for vault ${vault.vaultToken}:`, error); return []; } }); const chainIds = [...new Set((await Promise.all(chainIdsPromises)).flat())]; const rewardsPromises = chainIds.map(async (chainId) => { try { const response = await fetch(`https://api.merkl.xyz/v4/users/${account}/rewards?chainId=${chainId}&test=false&breakdownPage=0&reloadChainId=${chainId}`, { headers: fetch_headers_js_1.MOONWELL_FETCH_JSON_HEADERS, }); if (!response.ok) { console.warn(`Merkl API request failed: ${response.status} ${response.statusText}`); return []; } return (await response.json()); } catch (error) { console.warn(`Error fetching Merkl rewards for chain ${chainId}:`, error); return []; } }); const allRewards = await Promise.all(rewardsPromises); return allRewards.flat(); } catch (error) { console.error("Error in getMerklRewardsData:", error); return []; } } //# sourceMappingURL=common.js.map