@cfxdevkit/defillama
Version:
A TypeScript library for interacting with Defillama API
313 lines • 14.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProtocolAnalyzer = void 0;
// New file for analysis-related formatting
const index_1 = require("./index");
class ProtocolAnalyzer {
static analyzeProtocolData(data) {
// Extract Protocol Info with safe defaults
const info = {
name: data.name || "Unknown",
address: data.address ? data.address.split(":")[1] : "",
symbol: data.symbol || "",
url: data.url || "",
description: data.description || "",
chains: Array.isArray(data.chains) ? data.chains : [],
logo: data.logo || "",
audits: typeof data.audits === "string" ? parseInt(data.audits) : 0,
audit_note: data.audit_note || null,
category: data.category || "Unknown",
oracles: Array.isArray(data.oracles) ? data.oracles : [],
forkedFrom: Array.isArray(data.forkedFrom) ? data.forkedFrom : [],
twitter: data.twitter ? `https://x.com/${data.twitter}` : "",
audit_links: Array.isArray(data.audit_links) ? data.audit_links : [],
listedAt: data.listedAt ? new Date(data.listedAt * 1000) : new Date(),
github: Array.isArray(data.github)
? data.github.map((repo) => `https://github.com/${repo}`)
: [],
currentChainTvls: typeof data.currentChainTvls === "object" ? data.currentChainTvls : {},
};
// Get TVL data with safety checks
const rawTvlData = data.chainTvls?.[data.chain]?.tvl || data.tvl || [];
if (!Array.isArray(rawTvlData)) {
throw new Error(`Invalid TVL data structure for protocol ${data.name}`);
}
// Analyze TVL Data with safe value extraction
const tvlData = rawTvlData
.filter((entry) => entry && typeof entry.date === "number")
.map((entry) => ({
date: new Date(entry.date * 1000),
tvl: entry.totalLiquidityUSD || (entry.tokens ? Object.values(entry.tokens)[0] : 0),
}))
.filter((entry) => entry.tvl !== undefined && entry.tvl !== null && !isNaN(entry.tvl));
// Add safety check
if (tvlData.length === 0) {
throw new Error(`No valid TVL data found for protocol ${data.name}`);
}
// Helper function to calculate statistics
const calculateStats = (tvlValues) => {
if (tvlValues.length === 0)
return { avg: 0, min: 0, max: 0, volatility: 0 };
const avg = tvlValues.reduce((a, b) => a + b, 0) / tvlValues.length;
return {
avg,
min: Math.min(...tvlValues),
max: Math.max(...tvlValues),
volatility: Math.sqrt(tvlValues.reduce((sum, val) => sum + Math.pow(val - avg, 2), 0) / tvlValues.length),
};
};
// Group by month with safety checks
const monthlyData = tvlData.reduce((acc, { date, tvl }) => {
if (!date || typeof tvl !== "number")
return acc;
const monthKey = date.toISOString().slice(0, 7);
if (!acc[monthKey]) {
acc[monthKey] = {
tvls: [],
startTVL: tvl,
endTVL: tvl,
};
}
acc[monthKey].tvls.push(tvl);
acc[monthKey].endTVL = tvl;
return acc;
}, {});
// Group by year with safety checks
const yearlyData = tvlData.reduce((acc, { date, tvl }) => {
if (!date || typeof tvl !== "number")
return acc;
const year = date.getFullYear();
if (!acc[year]) {
acc[year] = {
tvls: [],
startTVL: tvl,
endTVL: tvl,
};
}
acc[year].tvls.push(tvl);
acc[year].endTVL = tvl;
return acc;
}, {});
const byMonth = Object.entries(monthlyData).map(([month, data]) => {
const stats = calculateStats(data.tvls);
return {
month,
avgTVL: stats.avg,
minTVL: stats.min,
maxTVL: stats.max,
startTVL: data.startTVL,
endTVL: data.endTVL,
changePercent: ((data.endTVL - data.startTVL) / data.startTVL) * 100,
};
});
const byYear = Object.entries(yearlyData).map(([year, data]) => {
const stats = calculateStats(data.tvls);
return {
year: parseInt(year),
avgTVL: stats.avg,
minTVL: stats.min,
maxTVL: stats.max,
startTVL: data.startTVL,
endTVL: data.endTVL,
changePercent: ((data.endTVL - data.startTVL) / data.startTVL) * 100,
};
});
const overallStats = calculateStats(tvlData.map((d) => d.tvl));
const tvlAnalysis = {
byMonth,
byYear,
overall: {
avgTVL: overallStats.avg,
minTVL: overallStats.min,
maxTVL: overallStats.max,
startTVL: tvlData[0].tvl,
currentTVL: tvlData[tvlData.length - 1].tvl,
totalChangePercent: ((tvlData[tvlData.length - 1].tvl - tvlData[0].tvl) / tvlData[0].tvl) * 100,
volatility: overallStats.volatility,
},
};
return { info, tvlAnalysis };
}
static formatProtocolAnalysis(data) {
const analysis = this.analyzeProtocolData(data);
return {
protocolInfo: {
name: analysis.info.name,
address: analysis.info.address,
symbol: analysis.info.symbol,
url: analysis.info.url,
description: analysis.info.description,
chains: analysis.info.chains,
logo: analysis.info.logo,
audits: analysis.info.audits,
audit_note: analysis.info.audit_note,
category: analysis.info.category,
oracles: analysis.info.oracles,
forkedFrom: analysis.info.forkedFrom,
twitter: analysis.info.twitter,
audit_links: analysis.info.audit_links,
listedAt: index_1.formatUtils.monthYear(analysis.info.listedAt),
github: analysis.info.github,
currentChainTvls: Object.entries(analysis.info.currentChainTvls).reduce((acc, [chain, value]) => ({
...acc,
[chain]: index_1.formatUtils.compactCurrency(value),
}), {}),
},
tvlAnalysis: {
overall: {
currentTVL: index_1.formatUtils.compactCurrency(analysis.tvlAnalysis.overall.currentTVL),
startingTVL: index_1.formatUtils.compactCurrency(analysis.tvlAnalysis.overall.startTVL),
averageTVL: index_1.formatUtils.compactCurrency(analysis.tvlAnalysis.overall.avgTVL),
minimumTVL: index_1.formatUtils.compactCurrency(analysis.tvlAnalysis.overall.minTVL),
maximumTVL: index_1.formatUtils.compactCurrency(analysis.tvlAnalysis.overall.maxTVL),
totalChange: index_1.formatUtils.changePercent(analysis.tvlAnalysis.overall.totalChangePercent),
volatility: analysis.tvlAnalysis.overall.volatility,
},
yearlyAnalysis: analysis.tvlAnalysis.byYear.map((year) => ({
year: year.year,
average: index_1.formatUtils.compactCurrency(year.avgTVL),
minimum: index_1.formatUtils.compactCurrency(year.minTVL),
maximum: index_1.formatUtils.compactCurrency(year.maxTVL),
startingTVL: index_1.formatUtils.compactCurrency(year.startTVL),
endingTVL: index_1.formatUtils.compactCurrency(year.endTVL),
percentageChange: index_1.formatUtils.changePercent(year.changePercent),
})),
monthlyAnalysis: analysis.tvlAnalysis.byMonth.map((month) => ({
month: index_1.formatUtils.monthYear(new Date(month.month)),
average: index_1.formatUtils.compactCurrency(month.avgTVL),
minimum: index_1.formatUtils.compactCurrency(month.minTVL),
maximum: index_1.formatUtils.compactCurrency(month.maxTVL),
startingTVL: index_1.formatUtils.compactCurrency(month.startTVL),
endingTVL: index_1.formatUtils.compactCurrency(month.endTVL),
percentageChange: index_1.formatUtils.changePercent(month.changePercent),
})),
},
};
}
static analyzeChainTVLData(data) {
// Convert UNIX timestamps to Date objects and structure the data
const tvlData = data
.filter((entry) => entry && typeof entry.date === "number" && !isNaN(entry.tvl))
.map((entry) => ({
date: new Date(entry.date * 1000),
tvl: entry.tvl,
}));
if (tvlData.length === 0) {
throw new Error("No valid TVL data found for chain");
}
// Helper function to calculate statistics
const calculateStats = (tvlValues) => {
if (tvlValues.length === 0)
return { avg: 0, min: 0, max: 0, volatility: 0 };
const avg = tvlValues.reduce((a, b) => a + b, 0) / tvlValues.length;
return {
avg,
min: Math.min(...tvlValues),
max: Math.max(...tvlValues),
volatility: Math.sqrt(tvlValues.reduce((sum, val) => sum + Math.pow(val - avg, 2), 0) / tvlValues.length),
};
};
// Group by month
const monthlyData = tvlData.reduce((acc, { date, tvl }) => {
const monthKey = date.toISOString().slice(0, 7);
if (!acc[monthKey]) {
acc[monthKey] = {
tvls: [],
startTVL: tvl,
endTVL: tvl,
};
}
acc[monthKey].tvls.push(tvl);
acc[monthKey].endTVL = tvl;
return acc;
}, {});
// Group by year
const yearlyData = tvlData.reduce((acc, { date, tvl }) => {
const year = date.getFullYear();
if (!acc[year]) {
acc[year] = {
tvls: [],
startTVL: tvl,
endTVL: tvl,
};
}
acc[year].tvls.push(tvl);
acc[year].endTVL = tvl;
return acc;
}, {});
const byMonth = Object.entries(monthlyData).map(([month, data]) => {
const stats = calculateStats(data.tvls);
return {
month,
avgTVL: stats.avg,
minTVL: stats.min,
maxTVL: stats.max,
startTVL: data.startTVL,
endTVL: data.endTVL,
changePercent: ((data.endTVL - data.startTVL) / data.startTVL) * 100,
};
});
const byYear = Object.entries(yearlyData).map(([year, data]) => {
const stats = calculateStats(data.tvls);
return {
year: parseInt(year),
avgTVL: stats.avg,
minTVL: stats.min,
maxTVL: stats.max,
startTVL: data.startTVL,
endTVL: data.endTVL,
changePercent: ((data.endTVL - data.startTVL) / data.startTVL) * 100,
};
});
const overallStats = calculateStats(tvlData.map((d) => d.tvl));
return {
byMonth,
byYear,
overall: {
avgTVL: overallStats.avg,
minTVL: overallStats.min,
maxTVL: overallStats.max,
startTVL: tvlData[0].tvl,
currentTVL: tvlData[tvlData.length - 1].tvl,
totalChangePercent: ((tvlData[tvlData.length - 1].tvl - tvlData[0].tvl) / tvlData[0].tvl) * 100,
volatility: overallStats.volatility,
},
};
}
static formatChainTVLAnalysis(data) {
const analysis = this.analyzeChainTVLData(data);
return {
chainAnalysis: {
overall: {
currentTVL: index_1.formatUtils.compactCurrency(analysis.overall.currentTVL),
startingTVL: index_1.formatUtils.compactCurrency(analysis.overall.startTVL),
averageTVL: index_1.formatUtils.compactCurrency(analysis.overall.avgTVL),
minimumTVL: index_1.formatUtils.compactCurrency(analysis.overall.minTVL),
maximumTVL: index_1.formatUtils.compactCurrency(analysis.overall.maxTVL),
totalChange: index_1.formatUtils.changePercent(analysis.overall.totalChangePercent),
volatility: analysis.overall.volatility,
},
yearlyAnalysis: analysis.byYear.map((year) => ({
year: year.year,
average: index_1.formatUtils.compactCurrency(year.avgTVL),
minimum: index_1.formatUtils.compactCurrency(year.minTVL),
maximum: index_1.formatUtils.compactCurrency(year.maxTVL),
startingTVL: index_1.formatUtils.compactCurrency(year.startTVL),
endingTVL: index_1.formatUtils.compactCurrency(year.endTVL),
percentageChange: index_1.formatUtils.changePercent(year.changePercent),
})),
monthlyAnalysis: analysis.byMonth.map((month) => ({
month: index_1.formatUtils.monthYear(new Date(month.month)),
average: index_1.formatUtils.compactCurrency(month.avgTVL),
minimum: index_1.formatUtils.compactCurrency(month.minTVL),
maximum: index_1.formatUtils.compactCurrency(month.maxTVL),
startingTVL: index_1.formatUtils.compactCurrency(month.startTVL),
endingTVL: index_1.formatUtils.compactCurrency(month.endTVL),
percentageChange: index_1.formatUtils.changePercent(month.changePercent),
})),
},
};
}
}
exports.ProtocolAnalyzer = ProtocolAnalyzer;
//# sourceMappingURL=analysis.js.map