UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

114 lines 5.15 kB
import { MOONWELL_FETCH_JSON_HEADERS } from "../../common/fetch-headers.js"; const MOONWELL_MERKL_CREATOR = "0x8b621804a7637b781e2BbD58e256a591F2dF7d51"; const CAMPAIGN_IDS_CACHE_TTL_MS = 4 * 60 * 60 * 1000; // 4 hours const MAX_BREAKDOWN_PAGES = 10; let campaignIdsCache = null; /** Resets the in-memory campaign IDs cache. Intended for use in tests only. */ export function resetMerklCampaignIdsCache() { campaignIdsCache = null; } /** * Fetches all Moonwell Merkl campaign IDs from the API. * Results are cached in memory for 4 hours since campaigns only change monthly. */ export async function getMerklCampaignIds() { const now = Date.now(); if (campaignIdsCache !== null && now - campaignIdsCache.fetchedAt < CAMPAIGN_IDS_CACHE_TTL_MS) { return campaignIdsCache.ids; } try { const response = await fetch(`https://api.merkl.xyz/v4/campaigns?creatorAddress=${MOONWELL_MERKL_CREATOR}&excludeSubCampaigns=true&items=100`, { headers: MOONWELL_FETCH_JSON_HEADERS }); if (!response.ok) { console.warn(`Merkl API request failed: ${response.status} ${response.statusText}`); return campaignIdsCache?.ids ?? []; } const data = (await response.json()); const ids = data.map((c) => c.campaignId); campaignIdsCache = { ids, fetchedAt: now }; return ids; } catch (error) { console.error("Error in getMerklCampaignIds:", error); return campaignIdsCache?.ids ?? []; } } export async function getMerklRewardsData(campaignId, chainId, account) { try { const page0Response = await fetch(`https://api.merkl.xyz/v4/users/${account}/rewards?chainId=${chainId}&test=false&breakdownPage=0&reloadChainId=${chainId}`, { headers: MOONWELL_FETCH_JSON_HEADERS, }); if (!page0Response.ok) { console.warn(`Merkl API request failed: ${page0Response.status} ${page0Response.statusText}`); return []; } const data = (await page0Response.json()); if (data.length === 0) { return []; } // Paginate through remaining breakdown pages to collect all breakdowns for (let page = 1; page < MAX_BREAKDOWN_PAGES; page++) { const pageResponse = await fetch(`https://api.merkl.xyz/v4/users/${account}/rewards?chainId=${chainId}&test=false&breakdownPage=${page}&reloadChainId=${chainId}`, { headers: MOONWELL_FETCH_JSON_HEADERS, }); if (!pageResponse.ok) { break; } const pageData = (await pageResponse.json()); const allBreakdownsEmpty = pageData.every((reward) => reward.rewards.every((r) => r.breakdowns.length === 0)); if (allBreakdownsEmpty) { break; } // Merge breakdowns from this page into the page-0 data for (const pageReward of pageData) { const baseReward = data.find((d) => d.chain.id === pageReward.chain.id); if (!baseReward) continue; for (const pageRewardEntry of pageReward.rewards) { const baseRewardEntry = baseReward.rewards.find((r) => r.token.address.toLowerCase() === pageRewardEntry.token.address.toLowerCase()); if (baseRewardEntry) { baseRewardEntry.breakdowns.push(...pageRewardEntry.breakdowns); } } } } return data .filter((reward) => reward.rewards.some((r) => r.breakdowns.some((b) => campaignId.includes(b.campaignId)))) .flatMap((reward) => reward.rewards .filter((r) => r.breakdowns.some((b) => campaignId.includes(b.campaignId))) .flatMap((r) => r.breakdowns .filter((b) => campaignId.includes(b.campaignId)) .map((b) => ({ chain: reward.chain.id, token: r.token, amount: b.amount, claimed: b.claimed, pending: b.pending, })))); } catch (error) { console.error("Error in getMerklRewardsData:", error); return []; } } export async function getMerklStakingApr(contractAddress) { const now = Math.floor(Date.now() / 1000); try { const response = await fetch(`https://api.merkl.xyz/v4/campaigns?creatorAddress=${MOONWELL_MERKL_CREATOR}&excludeSubCampaigns=true&items=100`, { headers: MOONWELL_FETCH_JSON_HEADERS }); if (!response.ok) { console.warn(`Merkl API request failed: ${response.status} ${response.statusText}`); return 0; } const data = (await response.json()); return data .filter((c) => c.startTimestamp <= now && c.endTimestamp >= now) .filter((c) => c.params.targetToken.toLowerCase() === contractAddress.toLowerCase()) .reduce((acc, c) => acc + Number(c.apr), 0); } catch (error) { console.error("Error in getMerklStakingApr:", error); return 0; } } //# sourceMappingURL=common.js.map