diff --git a/docs/node-ops/staking-and-delegation.mdx b/docs/node-ops/staking-and-delegation.mdx index 824316d6d..544cc368c 100644 --- a/docs/node-ops/staking-and-delegation.mdx +++ b/docs/node-ops/staking-and-delegation.mdx @@ -21,7 +21,7 @@ This page explains how staking and delegation works, including how to stake as a The Lit Protocol employs a dual reward structure to compensate node operators: 1. **Cost-Based Component** -A baseline reward is allocated to each node operator to offset the expenses associated with the required hardware and infrastructure. The baseline reward amount may be adjusted periodically via governance to cover the real-world costs associated with node operations (e.g., server hosting) in their entirety, ensuring operators always break even on the costs associated with running a node and never operate at a net loss. The goal is to preserve a stable pool of node operators even during periods of market volatility, essential for maintaining the shared cryptographic secrets maintained by the network in perpetuity. +A baseline reward of $1,500 in LITKEY tokens is allocated to each node operator to offset the expenses associated with the required hardware and infrastructure. The baseline reward amount may be adjusted periodically via governance to cover the real-world costs associated with node operations (e.g., server hosting) in their entirety, ensuring operators always break even on the costs associated with running a node and never operate at a net loss. The goal is to preserve a stable pool of node operators even during periods of market volatility, essential for maintaining the shared cryptographic secrets maintained by the network in perpetuity. Several configurable parameters go into setting the cost-based component of the Lit node rewards budget, including the price of the \$LITKEY token, the costs associated with running a node (denominated in USD), and a target profit margin factor. diff --git a/docs/snippets/CurrentPricesTable.jsx b/docs/snippets/CurrentPricesTable.jsx index cf3a24555..fdd7e87a9 100644 --- a/docs/snippets/CurrentPricesTable.jsx +++ b/docs/snippets/CurrentPricesTable.jsx @@ -17,7 +17,6 @@ export const CurrentPricesTable = ({ priceData }) => { const PRODUCT_IDS = [ ProductId.PkpSign, ProductId.EncSign, - ProductId.LitAction, ProductId.SignSessionKey, ]; diff --git a/docs/snippets/PriceProvider.jsx b/docs/snippets/PriceProvider.jsx index 863766a77..0d3dd191d 100644 --- a/docs/snippets/PriceProvider.jsx +++ b/docs/snippets/PriceProvider.jsx @@ -265,13 +265,58 @@ export const PriceProvider = ({ children, component: Component }) => { const basePrice = basePricesResult[0]; const maxPrice = maxPricesResult[0]; - // Calculate usage percent: (current - base) / (max - base) * 100 - // Average the prices from all nodes + // Calculate usage percent by finding which usage percentage produces the current price + // Use median price from all nodes to get current market price let calculatedUsage = 0; if (nodePriceData.length > 0 && !maxPrice.eq(basePrice)) { - const avgPrice = nodePriceData.reduce((sum, node) => sum.add(node.price), ethers.BigNumber.from(0)).div(nodePriceData.length); - calculatedUsage = avgPrice.sub(basePrice).mul(100).div(maxPrice.sub(basePrice)).toNumber(); + // Extract and sort all node prices + const prices = nodePriceData.map(node => ethers.BigNumber.from(node.price)); + prices.sort((a, b) => { + if (a.lt(b)) return -1; + if (a.gt(b)) return 1; + return 0; + }); + + // Calculate median + let medianPrice; + const mid = Math.floor(prices.length / 2); + if (prices.length % 2 === 0) { + // Even number of prices: average the two middle values + medianPrice = prices[mid - 1].add(prices[mid]).div(2); + } else { + // Odd number of prices: use the middle value + medianPrice = prices[mid]; + } + + // Debug: log values to understand why calculation might fail + console.log('Usage calculation:', { + nodePrices: nodePriceData.map(n => n.price.toString()), + sortedPrices: prices.map(p => p.toString()), + medianPrice: medianPrice.toString(), + basePrice: basePrice.toString(), + maxPrice: maxPrice.toString(), + medianVsBase: medianPrice.lt(basePrice) ? 'median < base' : medianPrice.eq(basePrice) ? 'median = base' : 'median > base', + }); + + // If medianPrice equals basePrice, usage is 0% + if (medianPrice.lte(basePrice)) { + calculatedUsage = 0; + } + // If medianPrice equals or exceeds maxPrice, usage is 100% + else if (medianPrice.gte(maxPrice)) { + calculatedUsage = 100; + } + // Otherwise, calculate: (medianPrice - basePrice) * 100 / (maxPrice - basePrice) + else { + const priceDiff = medianPrice.sub(basePrice); + const maxBaseDiff = maxPrice.sub(basePrice); + // Calculate percentage (0-100) with integer precision + calculatedUsage = priceDiff.mul(100).div(maxBaseDiff).toNumber(); + // Ensure it's between 0 and 100 + calculatedUsage = Math.max(0, Math.min(100, calculatedUsage)); + } } + console.log('Calculated usage:', calculatedUsage); setUsagePercent(calculatedUsage); const currentPricesResult = await contract.usagePercentToPrices(calculatedUsage, PRODUCT_IDS);