> ## Documentation Index
> Fetch the complete documentation index at: https://litprotocol-chore-cleanup-explorer.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Current Prices

export const PriceCalculator = ({priceData}) => {
  const LitActionPriceComponent = window.LitPricingConstants?.LitActionPriceComponent || ({});
  const LIT_ACTION_COMPONENT_NAMES = window.LitPricingConstants?.LIT_ACTION_COMPONENT_NAMES || ({});
  const NodePriceMeasurement = window.LitPricingConstants?.NodePriceMeasurement || ({});
  const MEASUREMENT_NAMES = window.LitPricingConstants?.MEASUREMENT_NAMES || ({});
  const weiToTokens = window.LitPricingConstants?.weiToTokens || (() => 0);
  const formatPrice = window.LitPricingConstants?.formatPrice || (price => String(price));
  const [pkpSignCount, setPkpSignCount] = useState(0);
  const [encSignCount, setEncSignCount] = useState(0);
  const [sessionKeyCount, setSessionKeyCount] = useState(0);
  const [pkpMintCount, setPkpMintCount] = useState(0);
  const [litActionBaseCount, setLitActionBaseCount] = useState(0);
  const [litActionRuntimeSeconds, setLitActionRuntimeSeconds] = useState(0);
  const [litActionMemoryMB, setLitActionMemoryMB] = useState(0);
  const [litActionCodeLength, setLitActionCodeLength] = useState(0);
  const [litActionResponseLength, setLitActionResponseLength] = useState(0);
  const [litActionSignatures, setLitActionSignatures] = useState(0);
  const [litActionBroadcasts, setLitActionBroadcasts] = useState(0);
  const [litActionContractCalls, setLitActionContractCalls] = useState(0);
  const [litActionCallDepth, setLitActionCallDepth] = useState(0);
  const [litActionDecrypts, setLitActionDecrypts] = useState(0);
  const [litActionFetches, setLitActionFetches] = useState(0);
  const {loading, error, currentPrices, litActionConfigs, litKeyPriceUSD, pkpMintCost, numberOfNodes, thresholdNodes, ethers} = priceData || ({});
  const nodeInfo = thresholdNodes !== null && numberOfNodes !== null ? <p style={{
    marginBottom: '15px',
    fontSize: '0.85em',
    color: 'var(--mint-text-secondary, #666)',
    fontStyle: 'italic'
  }}>
      <strong>Note:</strong> Prices shown are per request (on-chain prices × {thresholdNodes} threshold nodes). 
      On-chain prices are per node, but since your request goes to {thresholdNodes} nodes (2/3 of {numberOfNodes} total nodes, minimum 3) and each node charges the product price, 
      the total cost per request is the product price multiplied by {thresholdNodes}.
    </p> : null;
  const totalTokens = useMemo(() => {
    if (!currentPrices || !litActionConfigs || !ethers || !thresholdNodes) return 0;
    let total = 0;
    const addPrice = (price, count) => {
      if (price != null) {
        total += count * weiToTokens(price, ethers) * thresholdNodes;
      }
    };
    addPrice(currentPrices[0], pkpSignCount);
    addPrice(currentPrices[1], encSignCount);
    addPrice(currentPrices[2], sessionKeyCount);
    if (pkpMintCost != null) {
      total += pkpMintCount * weiToTokens(pkpMintCost, ethers);
    }
    litActionConfigs.forEach(config => {
      const component = Number(config.priceComponent);
      const counts = [litActionBaseCount, litActionRuntimeSeconds, litActionMemoryMB, litActionCodeLength, litActionResponseLength, litActionSignatures, litActionBroadcasts, litActionContractCalls, litActionCallDepth, litActionDecrypts, litActionFetches];
      if (component < counts.length) {
        addPrice(config.price, counts[component]);
      }
    });
    return total;
  }, [pkpSignCount, encSignCount, sessionKeyCount, pkpMintCount, litActionBaseCount, litActionRuntimeSeconds, litActionMemoryMB, litActionCodeLength, litActionResponseLength, litActionSignatures, litActionBroadcasts, litActionContractCalls, litActionCallDepth, litActionDecrypts, litActionFetches, currentPrices, litActionConfigs, pkpMintCost, thresholdNodes, ethers]);
  const totalUSD = litKeyPriceUSD ? totalTokens * litKeyPriceUSD : null;
  if (!priceData) {
    return <div style={{
      padding: '20px',
      textAlign: 'center'
    }}>
        <p>Price data not available. Please wrap this component with PriceProvider.</p>
      </div>;
  }
  if (loading) {
    return <div style={{
      padding: '20px',
      textAlign: 'center'
    }}>
        <p>Loading pricing data...</p>
      </div>;
  }
  if (error) {
    return <div style={{
      padding: '20px',
      color: 'red'
    }}>
        <p>Error loading prices: {error}</p>
      </div>;
  }
  const renderNumberInput = (label, value, onChange, step = 1, min = 0, allowDecimals = false) => {
    const handleChange = e => {
      const newValue = e.target.value;
      if (newValue === '') {
        onChange(0);
        return;
      }
      const parsed = allowDecimals ? parseFloat(newValue) : parseInt(newValue, 10);
      if (!isNaN(parsed)) {
        const validated = Math.max(min, parsed);
        onChange(validated);
      }
    };
    const handleIncrement = () => {
      const newValue = value + step;
      onChange(Math.max(min, allowDecimals ? newValue : Math.round(newValue)));
    };
    const handleDecrement = () => {
      const newValue = value - step;
      onChange(Math.max(min, allowDecimals ? newValue : Math.round(newValue)));
    };
    return <div key={label} style={{
      marginBottom: '15px'
    }}>
        <label style={{
      display: 'block',
      marginBottom: '5px',
      fontSize: '0.9em',
      fontWeight: '500',
      color: 'var(--mint-text, inherit)'
    }}>
          {label}
        </label>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '10px'
    }}>
          <button onClick={handleDecrement} style={{
      padding: '8px 12px',
      fontSize: '1em',
      cursor: 'pointer',
      border: '1px solid var(--mint-border, #ddd)',
      borderRadius: '4px',
      backgroundColor: 'var(--mint-bg-secondary, #f5f5f5)',
      color: 'var(--mint-text, inherit)'
    }}>
            -
          </button>
          <input type="number" value={value || ''} onChange={handleChange} step={step} min={min} style={{
      flex: 1,
      padding: '8px',
      fontSize: '0.9em',
      border: '1px solid var(--mint-border, #ddd)',
      borderRadius: '4px',
      backgroundColor: 'var(--mint-bg-secondary, #f5f5f5)',
      color: 'var(--mint-text, inherit)'
    }} />
          <button onClick={handleIncrement} style={{
      padding: '8px 12px',
      fontSize: '1em',
      cursor: 'pointer',
      border: '1px solid var(--mint-border, #ddd)',
      borderRadius: '4px',
      backgroundColor: 'var(--mint-bg-secondary, #f5f5f5)',
      color: 'var(--mint-text, inherit)'
    }}>
            +
          </button>
        </div>
      </div>;
  };
  return <div style={{
    marginTop: '30px',
    marginBottom: '30px',
    padding: '20px',
    border: '1px solid var(--mint-border, #ddd)',
    borderRadius: '8px'
  }}>
      {nodeInfo}
      <h4 style={{
    marginTop: 0,
    marginBottom: '15px',
    fontSize: '1em',
    color: 'var(--mint-text, inherit)'
  }}>Basic Network Operations</h4>
      <div style={{
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
    gap: '20px',
    marginBottom: '20px'
  }}>
        {}
        <div>
          {renderNumberInput("PKP Sign Operations", pkpSignCount, setPkpSignCount)}
          {renderNumberInput("Encrypted Sign Operations", encSignCount, setEncSignCount)}
        </div>

        <div>
          {renderNumberInput("Sign Session Key Operations", sessionKeyCount, setSessionKeyCount)}
          {renderNumberInput("PKP Minting", pkpMintCount, setPkpMintCount)}
        </div>
      </div>

      <h4 style={{
    marginTop: 0,
    marginBottom: '15px',
    fontSize: '1em',
    color: 'var(--mint-text, inherit)'
  }}>Lit Action Operations</h4>
      <div style={{
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
    gap: '20px',
    marginBottom: '20px'
  }}>
        {}
        <div>
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.baseAmount]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perCount]}`, litActionBaseCount, setLitActionBaseCount)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.runtimeLength]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perSecond]}`, litActionRuntimeSeconds, setLitActionRuntimeSeconds, 0.1, 0, true)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.memoryUsage]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perMegabyte]}`, litActionMemoryMB, setLitActionMemoryMB, 0.1, 0, true)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.codeLength]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perMegabyte]}`, litActionCodeLength, setLitActionCodeLength, 0.1, 0, true)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.responseLength]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perMegabyte]}`, litActionResponseLength, setLitActionResponseLength, 0.1, 0, true)}
        </div>
        <div>
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.signatures]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perCount]}`, litActionSignatures, setLitActionSignatures)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.broadcasts]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perCount]}`, litActionBroadcasts, setLitActionBroadcasts)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.contractCalls]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perCount]}`, litActionContractCalls, setLitActionContractCalls)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.callDepth]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perCount]}`, litActionCallDepth, setLitActionCallDepth)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.decrypts]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perCount]}`, litActionDecrypts, setLitActionDecrypts)}
          {renderNumberInput(`${LIT_ACTION_COMPONENT_NAMES[LitActionPriceComponent.fetches]} ${MEASUREMENT_NAMES[NodePriceMeasurement.perCount]}`, litActionFetches, setLitActionFetches)}
        </div>
      </div>

      {}
      <div style={{
    marginTop: '30px',
    padding: '20px',
    backgroundColor: 'var(--mint-bg-secondary, #f9f9f9)',
    borderRadius: '8px',
    textAlign: 'right'
  }}>
        <h4 style={{
    marginTop: 0,
    marginBottom: '10px',
    textAlign: 'right',
    color: 'var(--mint-text, inherit)'
  }}>
          Estimated Total Cost
        </h4>
        <div style={{
    fontSize: '1.5em',
    fontWeight: 'bold',
    fontFamily: 'monospace',
    color: 'var(--mint-primary, #0066cc)',
    textAlign: 'right'
  }}>
          {formatPrice(totalTokens, totalUSD)}
        </div>
        <button onClick={() => {
    setPkpSignCount(0);
    setEncSignCount(0);
    setSessionKeyCount(0);
    setPkpMintCount(0);
    setLitActionBaseCount(0);
    setLitActionRuntimeSeconds(0);
    setLitActionMemoryMB(0);
    setLitActionCodeLength(0);
    setLitActionResponseLength(0);
    setLitActionSignatures(0);
    setLitActionBroadcasts(0);
    setLitActionContractCalls(0);
    setLitActionCallDepth(0);
    setLitActionDecrypts(0);
    setLitActionFetches(0);
  }} style={{
    marginTop: '15px',
    padding: '10px 20px',
    fontSize: '0.9em',
    cursor: 'pointer',
    border: '1px solid var(--mint-border, #ddd)',
    borderRadius: '4px',
    backgroundColor: 'var(--mint-bg-secondary, #f5f5f5)',
    color: 'var(--mint-text, inherit)',
    textAlign: 'right'
  }}>
          Reset All Values
        </button>
      </div>
    </div>;
};

export const PriceProvider = ({children, component: Component}) => {
  const NAGA_PROD_PRICE_FEED_ADDRESS = '0x88F5535Fa6dA5C225a3C06489fE4e3405b87608C';
  const NAGA_PROD_PKP_ADDRESS = '0x11eBfFeab32f6cb5775BeF83E09124B9322E4026';
  const RPC_URL = 'https://lit-chain-rpc.litprotocol.com/';
  const ProductId = {
    PkpSign: 0,
    EncSign: 1,
    LitAction: 2,
    SignSessionKey: 3
  };
  const PRODUCT_IDS = [ProductId.PkpSign, ProductId.EncSign, ProductId.LitAction, ProductId.SignSessionKey];
  const PRODUCT_META = [{
    id: ProductId.PkpSign,
    key: 'PkpSign',
    name: 'PKP Sign'
  }, {
    id: ProductId.EncSign,
    key: 'EncSign',
    name: 'Encrypted Sign'
  }, {
    id: ProductId.LitAction,
    key: 'LitAction',
    name: 'Lit Action'
  }, {
    id: ProductId.SignSessionKey,
    key: 'SignSessionKey',
    name: 'Sign Session Key'
  }];
  const getProductMeta = productId => PRODUCT_META.find(p => p.id === productId) || ({
    id: productId,
    key: `Product_${productId}`,
    name: `Product ${productId}`
  });
  const debugPricingLog = (label, data) => {
    console.log(`[pricing] ${label}`, data);
  };
  const PRICE_FEED_ABI = [{
    inputs: [{
      internalType: 'uint256[]',
      name: 'productIds',
      type: 'uint256[]'
    }],
    name: 'baseNetworkPrices',
    outputs: [{
      internalType: 'uint256[]',
      name: '',
      type: 'uint256[]'
    }],
    stateMutability: 'view',
    type: 'function'
  }, {
    inputs: [{
      internalType: 'uint256[]',
      name: 'productIds',
      type: 'uint256[]'
    }],
    name: 'maxNetworkPrices',
    outputs: [{
      internalType: 'uint256[]',
      name: '',
      type: 'uint256[]'
    }],
    stateMutability: 'view',
    type: 'function'
  }, {
    inputs: [{
      internalType: 'uint256',
      name: 'usagePercent',
      type: 'uint256'
    }, {
      internalType: 'uint256[]',
      name: 'productIds',
      type: 'uint256[]'
    }],
    name: 'usagePercentToPrices',
    outputs: [{
      internalType: 'uint256[]',
      name: '',
      type: 'uint256[]'
    }],
    stateMutability: 'view',
    type: 'function'
  }, {
    inputs: [{
      internalType: 'uint256',
      name: 'productId',
      type: 'uint256'
    }],
    name: 'prices',
    outputs: [{
      components: [{
        internalType: 'address',
        name: 'stakerAddress',
        type: 'address'
      }, {
        internalType: 'uint256',
        name: 'price',
        type: 'uint256'
      }, {
        internalType: 'uint256',
        name: 'productId',
        type: 'uint256'
      }, {
        internalType: 'uint256',
        name: 'timestamp',
        type: 'uint256'
      }],
      internalType: 'struct LibPriceFeedStorage.NodePriceData[]',
      name: '',
      type: 'tuple[]'
    }],
    stateMutability: 'view',
    type: 'function'
  }, {
    inputs: [],
    name: 'getLitActionPriceConfigs',
    outputs: [{
      components: [{
        internalType: 'enum LibPriceFeedStorage.LitActionPriceComponent',
        name: 'priceComponent',
        type: 'uint8'
      }, {
        internalType: 'enum LibPriceFeedStorage.NodePriceMeasurement',
        name: 'priceMeasurement',
        type: 'uint8'
      }, {
        internalType: 'uint256',
        name: 'price',
        type: 'uint256'
      }],
      internalType: 'struct LibPriceFeedStorage.LitActionPriceConfig[]',
      name: '',
      type: 'tuple[]'
    }],
    stateMutability: 'view',
    type: 'function'
  }];
  const PKP_ABI = [{
    inputs: [],
    name: 'mintCost',
    outputs: [{
      internalType: 'uint256',
      name: '',
      type: 'uint256'
    }],
    stateMutability: 'view',
    type: 'function'
  }];
  const getLitKeyPrice = async () => {
    try {
      const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=lit-protocol&vs_currencies=usd');
      const data = await response.json();
      if (data['lit-protocol'] && data['lit-protocol'].usd) {
        return data['lit-protocol'].usd;
      }
      throw new Error('LIT price not found in CoinGecko response');
    } catch (error) {
      console.error('Error fetching LITKEY price from CoinGecko:', error);
      return null;
    }
  };
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [basePrices, setBasePrices] = useState([]);
  const [maxPrices, setMaxPrices] = useState([]);
  const [currentPrices, setCurrentPrices] = useState([]);
  const [litActionConfigs, setLitActionConfigs] = useState([]);
  const [litKeyPriceUSD, setLitKeyPriceUSD] = useState(null);
  const [usagePercent, setUsagePercent] = useState(null);
  const [pkpMintCost, setPkpMintCost] = useState(null);
  const [numberOfNodes, setNumberOfNodes] = useState(null);
  const [thresholdNodes, setThresholdNodes] = useState(null);
  const [ethersLoaded, setEthersLoaded] = useState(false);
  useEffect(() => {
    if (window.ethers) {
      setEthersLoaded(true);
      return;
    }
    const script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/ethers@5.7.2/dist/ethers.umd.min.js';
    script.onload = () => {
      setEthersLoaded(true);
    };
    script.onerror = () => {
      const fallbackScript = document.createElement('script');
      fallbackScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/ethers/5.7.2/ethers.umd.min.js';
      fallbackScript.onload = () => {
        setEthersLoaded(true);
      };
      fallbackScript.onerror = () => {
        setError('Failed to load ethers library from CDN');
        setLoading(false);
      };
      document.head.appendChild(fallbackScript);
    };
    document.head.appendChild(script);
    return () => {
      if (script.parentNode) {
        script.parentNode.removeChild(script);
      }
    };
  }, []);
  useEffect(() => {
    if (!ethersLoaded || !window.ethers) {
      return;
    }
    async function fetchPrices() {
      try {
        setLoading(true);
        setError(null);
        const {ethers} = window;
        const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
        const contract = new ethers.Contract(NAGA_PROD_PRICE_FEED_ADDRESS, PRICE_FEED_ABI, provider);
        const pkpContract = new ethers.Contract(NAGA_PROD_PKP_ADDRESS, PKP_ABI, provider);
        const priceUSD = await getLitKeyPrice();
        setLitKeyPriceUSD(priceUSD);
        const basePricesResult = await contract.baseNetworkPrices(PRODUCT_IDS);
        const maxPricesResult = await contract.maxNetworkPrices(PRODUCT_IDS);
        debugPricingLog('Fetched network price bands', {
          rpcUrl: RPC_URL,
          priceFeedAddress: NAGA_PROD_PRICE_FEED_ADDRESS,
          productIds: PRODUCT_IDS,
          products: PRODUCT_IDS.map((id, i) => ({
            productId: id,
            ...getProductMeta(id),
            basePriceWei: basePricesResult?.[i]?.toString?.(),
            maxPriceWei: maxPricesResult?.[i]?.toString?.()
          }))
        });
        const referenceProductId = ProductId.PkpSign;
        const referenceProductMeta = getProductMeta(referenceProductId);
        const nodePriceData = await contract.prices(referenceProductId);
        const totalNodes = nodePriceData.length;
        setNumberOfNodes(totalNodes);
        const calculatedThreshold = Math.floor(totalNodes * 2 / 3);
        const threshold = Math.max(3, calculatedThreshold);
        setThresholdNodes(threshold);
        const basePrice = basePricesResult[0];
        const maxPrice = maxPricesResult[0];
        let calculatedUsage = 0;
        let medianPriceForReferenceProduct = null;
        if (nodePriceData.length > 0 && !maxPrice.eq(basePrice)) {
          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;
          }).slice(0, threshold);
          let medianPrice;
          const mid = Math.floor(prices.length / 2);
          if (prices.length % 2 === 0) {
            medianPrice = prices[mid - 1].add(prices[mid]).div(2);
          } else {
            medianPrice = prices[mid];
          }
          medianPriceForReferenceProduct = medianPrice;
          console.log('Usage calculation:', {
            referenceProduct: referenceProductMeta,
            rpcUrl: RPC_URL,
            priceFeedAddress: NAGA_PROD_PRICE_FEED_ADDRESS,
            nodePrices: nodePriceData.map(n => n.price.toString()),
            sortedPrices: prices.map(p => p.toString()),
            medianPrice: medianPrice.toString(),
            basePrice: basePrice.toString(),
            maxPrice: maxPrice.toString(),
            maxEqualsBase: maxPrice.eq(basePrice),
            totalNodes,
            thresholdNodes: threshold,
            medianVsBase: medianPrice.lt(basePrice) ? 'median < base' : medianPrice.eq(basePrice) ? 'median = base' : 'median > base',
            minNodePrice: prices[0]?.toString?.(),
            maxNodePrice: prices[prices.length - 1]?.toString?.()
          });
          debugPricingLog('Node price samples (reference product)', {
            referenceProduct: referenceProductMeta,
            totalNodes,
            firstNodeSample: nodePriceData?.[0] ? {
              stakerAddress: nodePriceData[0].stakerAddress,
              productId: nodePriceData[0].productId?.toString?.(),
              priceWei: nodePriceData[0].price?.toString?.(),
              timestamp: nodePriceData[0].timestamp?.toString?.()
            } : null
          });
          if (medianPrice.lte(basePrice)) {
            calculatedUsage = 0;
          } else if (medianPrice.gte(maxPrice)) {
            calculatedUsage = 100;
          } else {
            const priceDiff = medianPrice.sub(basePrice);
            const maxBaseDiff = maxPrice.sub(basePrice);
            calculatedUsage = priceDiff.mul(100).div(maxBaseDiff).toNumber();
            calculatedUsage = Math.max(0, Math.min(100, calculatedUsage));
          }
        }
        console.log('Calculated usage:', {
          usagePercent: calculatedUsage,
          referenceProduct: referenceProductMeta
        });
        setUsagePercent(calculatedUsage);
        const currentPricesResult = await contract.usagePercentToPrices(calculatedUsage, PRODUCT_IDS);
        debugPricingLog('Derived current prices from usagePercentToPrices', {
          usagePercent: calculatedUsage,
          products: PRODUCT_IDS.map((id, i) => ({
            productId: id,
            ...getProductMeta(id),
            currentPriceWei: currentPricesResult?.[i]?.toString?.()
          }))
        });
        try {
          const derivedReferencePriceWei = currentPricesResult?.[0];
          if (medianPriceForReferenceProduct && derivedReferencePriceWei) {
            const diffWei = medianPriceForReferenceProduct.sub(derivedReferencePriceWei);
            debugPricingLog('Median vs derived reference price', {
              referenceProduct: referenceProductMeta,
              usagePercent: calculatedUsage,
              medianNodePriceWei: medianPriceForReferenceProduct.toString(),
              derivedReferencePriceWei: derivedReferencePriceWei.toString(),
              diffWei: diffWei.toString()
            });
          } else {
            debugPricingLog('Median vs derived reference price (skipped)', {
              referenceProduct: referenceProductMeta,
              usagePercent: calculatedUsage,
              reason: !medianPriceForReferenceProduct ? 'median price not available (no node prices or max==base)' : 'derived reference price not available'
            });
          }
        } catch (e) {
          debugPricingLog('Median vs derived reference price (error)', {
            referenceProduct: referenceProductMeta,
            usagePercent: calculatedUsage,
            error: e?.message || String(e)
          });
        }
        const litActionConfigsResult = await contract.getLitActionPriceConfigs();
        const mintCostResult = await pkpContract.mintCost();
        setPkpMintCost(mintCostResult);
        setBasePrices(basePricesResult);
        setMaxPrices(maxPricesResult);
        setCurrentPrices(currentPricesResult);
        setLitActionConfigs(litActionConfigsResult);
      } catch (err) {
        console.error('Error fetching prices:', err);
        setError(err.message || 'Failed to fetch prices');
      } finally {
        setLoading(false);
      }
    }
    fetchPrices();
  }, [ethersLoaded]);
  const priceData = {
    loading,
    error,
    basePrices,
    maxPrices,
    currentPrices,
    litActionConfigs,
    litKeyPriceUSD,
    usagePercent,
    pkpMintCost,
    numberOfNodes,
    thresholdNodes,
    ethers: window.ethers
  };
  const ComponentToRender = Component || (children && typeof children === 'function' ? children : null);
  if (!ComponentToRender) {
    return null;
  }
  if (typeof ComponentToRender === 'function') {
    return <ComponentToRender priceData={priceData} />;
  }
  return children;
};

export const CurrentPricesTable = ({priceData}) => {
  const PRODUCT_IDS = window.LitPricingConstants?.PRODUCT_IDS || [];
  const PRODUCT_NAMES = window.LitPricingConstants?.PRODUCT_NAMES || ({});
  const LIT_ACTION_COMPONENT_NAMES = window.LitPricingConstants?.LIT_ACTION_COMPONENT_NAMES || ({});
  const MEASUREMENT_NAMES = window.LitPricingConstants?.MEASUREMENT_NAMES || ({});
  const weiToTokens = window.LitPricingConstants?.weiToTokens || (() => 0);
  const formatPrice = window.LitPricingConstants?.formatPrice || (price => String(price));
  if (!priceData) {
    return <div style={{
      padding: '20px',
      textAlign: 'center'
    }}>
        <p>Price data not available. Please wrap this component with PriceProvider.</p>
      </div>;
  }
  const {loading, error, basePrices, maxPrices, currentPrices, litActionConfigs, litKeyPriceUSD, usagePercent, pkpMintCost, numberOfNodes, thresholdNodes, ethers} = priceData;
  if (loading) {
    return <div style={{
      padding: '20px',
      textAlign: 'center'
    }}>
        <p>Loading current prices from blockchain...</p>
      </div>;
  }
  if (error) {
    return <div style={{
      padding: '20px',
      color: 'red'
    }}>
        <p>Error loading prices: {error}</p>
        <p style={{
      fontSize: '0.9em',
      marginTop: '10px'
    }}>
          Unable to fetch pricing data. Please check your connection or try again later.
        </p>
      </div>;
  }
  return <div style={{
    marginTop: '20px',
    marginBottom: '20px',
    paddingLeft: '4px'
  }}>
      {litKeyPriceUSD && <p style={{
    marginBottom: '20px',
    fontSize: '0.9em',
    color: 'var(--mint-text-secondary, #666)'
  }}>
          <strong>LITKEY Price:</strong> ${litKeyPriceUSD.toFixed(4)} USD
          {usagePercent !== null && <span style={{
    marginLeft: '20px'
  }}>
              <strong>Estimated Network Usage:</strong> {usagePercent}%
            </span>}
          {numberOfNodes !== null && <span style={{
    marginLeft: '20px'
  }}>
              <strong>Total Nodes:</strong> {numberOfNodes}
            </span>}
          {thresholdNodes !== null && <span style={{
    marginLeft: '20px'
  }}>
              <strong>Threshold Nodes:</strong> {thresholdNodes}
            </span>}
        </p>}
      {thresholdNodes !== null && numberOfNodes !== null && <p style={{
    marginBottom: '20px',
    fontSize: '0.85em',
    color: 'var(--mint-text-secondary, #666)',
    fontStyle: 'italic'
  }}>
          <strong>Note:</strong> Prices shown are per request (on-chain prices × {thresholdNodes} threshold nodes). On-chain prices are per node, but since your request goes to {thresholdNodes} nodes (2/3 of {numberOfNodes} total nodes, minimum 3) and each node charges the product price, the total cost per request is the product price multiplied by {thresholdNodes}.
        </p>}

      <div style={{
    overflowX: 'auto',
    marginLeft: '0',
    marginRight: '0',
    paddingLeft: '0'
  }}>
        <table style={{
    width: '100%',
    maxWidth: '100%',
    borderCollapse: 'collapse',
    marginBottom: '30px',
    marginLeft: '0',
    marginRight: '0',
    tableLayout: 'auto'
  }}>
          <thead>
            <tr style={{
    backgroundColor: 'var(--mint-bg-secondary, #f5f5f5)'
  }}>
              <th style={{
    padding: '8px 6px 8px 8px',
    textAlign: 'left',
    border: '1px solid var(--mint-border, #ddd)',
    fontSize: '0.9em',
    color: 'var(--mint-text, inherit)'
  }}>
                Product
              </th>
              <th style={{
    padding: '8px 10px',
    textAlign: 'right',
    border: '1px solid var(--mint-border, #ddd)',
    fontSize: '0.9em',
    color: 'var(--mint-text, inherit)'
  }}>
                Current Price
              </th>
              <th style={{
    padding: '8px 10px',
    textAlign: 'right',
    border: '1px solid var(--mint-border, #ddd)',
    fontSize: '0.9em',
    color: 'var(--mint-text, inherit)'
  }}>
                Base Price
              </th>
              <th style={{
    padding: '8px 10px',
    textAlign: 'right',
    border: '1px solid var(--mint-border, #ddd)',
    fontSize: '0.9em',
    color: 'var(--mint-text, inherit)'
  }}>
                Max Price
              </th>
            </tr>
          </thead>
          <tbody>
            {PRODUCT_IDS.map((productId, index) => {
    const basePricePerNode = weiToTokens(basePrices[index], ethers);
    const maxPricePerNode = weiToTokens(maxPrices[index], ethers);
    const currentPricePerNode = weiToTokens(currentPrices[index], ethers);
    const basePriceInTokens = thresholdNodes ? basePricePerNode * thresholdNodes : basePricePerNode;
    const maxPriceInTokens = thresholdNodes ? maxPricePerNode * thresholdNodes : maxPricePerNode;
    const currentPriceInTokens = thresholdNodes ? currentPricePerNode * thresholdNodes : currentPricePerNode;
    const basePriceInUSD = litKeyPriceUSD ? basePriceInTokens * litKeyPriceUSD : null;
    const maxPriceInUSD = litKeyPriceUSD ? maxPriceInTokens * litKeyPriceUSD : null;
    const currentPriceInUSD = litKeyPriceUSD ? currentPriceInTokens * litKeyPriceUSD : null;
    return <tr key={productId}>
                  <td style={{
      padding: '8px 6px 8px 8px',
      border: '1px solid var(--mint-border, #ddd)',
      fontWeight: '500',
      fontSize: '0.9em'
    }}>
                    {PRODUCT_NAMES[productId]}
                  </td>
                  <td style={{
      padding: '8px 10px',
      textAlign: 'right',
      border: '1px solid var(--mint-border, #ddd)',
      fontFamily: 'monospace',
      fontWeight: '600',
      fontSize: '0.85em'
    }}>
                    {formatPrice(currentPriceInTokens, currentPriceInUSD)}
                  </td>
                  <td style={{
      padding: '8px 10px',
      textAlign: 'right',
      border: '1px solid var(--mint-border, #ddd)',
      fontFamily: 'monospace',
      fontSize: '0.85em'
    }}>
                    {formatPrice(basePriceInTokens, basePriceInUSD)}
                  </td>
                  <td style={{
      padding: '8px 10px',
      textAlign: 'right',
      border: '1px solid var(--mint-border, #ddd)',
      fontFamily: 'monospace',
      fontSize: '0.85em'
    }}>
                    {formatPrice(maxPriceInTokens, maxPriceInUSD)}
                  </td>
                </tr>;
  })}
            {pkpMintCost !== null && <tr>
                <td style={{
    padding: '8px 6px 8px 8px',
    border: '1px solid var(--mint-border, #ddd)',
    fontWeight: '500',
    fontSize: '0.9em'
  }}>
                  PKP Minting{' '}
                  <span style={{
    color: 'var(--mint-text-secondary, #666)',
    fontSize: '0.85em',
    fontWeight: 'normal',
    fontStyle: 'italic'
  }}>
                    (Static)
                  </span>
                </td>
                <td style={{
    padding: '8px 10px',
    textAlign: 'right',
    border: '1px solid var(--mint-border, #ddd)',
    fontFamily: 'monospace',
    fontWeight: '600',
    fontSize: '0.85em'
  }}>
                  {formatPrice(weiToTokens(pkpMintCost, ethers), litKeyPriceUSD ? weiToTokens(pkpMintCost, ethers) * litKeyPriceUSD : null)}
                </td>
                <td style={{
    padding: '8px 10px',
    textAlign: 'right',
    border: '1px solid var(--mint-border, #ddd)',
    fontFamily: 'monospace',
    fontSize: '0.85em'
  }}>
                  {formatPrice(weiToTokens(pkpMintCost, ethers), litKeyPriceUSD ? weiToTokens(pkpMintCost, ethers) * litKeyPriceUSD : null)}
                </td>
                <td style={{
    padding: '8px 10px',
    textAlign: 'right',
    border: '1px solid var(--mint-border, #ddd)',
    fontFamily: 'monospace',
    fontSize: '0.85em'
  }}>
                  {formatPrice(weiToTokens(pkpMintCost, ethers), litKeyPriceUSD ? weiToTokens(pkpMintCost, ethers) * litKeyPriceUSD : null)}
                </td>
              </tr>}
          </tbody>
        </table>
      </div>

      <h3 style={{
    marginTop: '40px',
    marginBottom: '20px'
  }}>
        Lit Action Price Components
      </h3>
      <div style={{
    overflowX: 'auto',
    marginLeft: '0',
    marginRight: '0',
    paddingLeft: '0'
  }}>
        <table style={{
    width: '100%',
    maxWidth: '100%',
    borderCollapse: 'collapse',
    marginLeft: '0',
    marginRight: '0',
    tableLayout: 'auto'
  }}>
          <thead>
            <tr style={{
    backgroundColor: 'var(--mint-bg-secondary, #f5f5f5)'
  }}>
              <th style={{
    padding: '8px 10px',
    textAlign: 'left',
    border: '1px solid var(--mint-border, #ddd)',
    fontSize: '0.9em',
    color: 'var(--mint-text, inherit)'
  }}>
                Component
              </th>
              <th style={{
    padding: '8px 10px',
    textAlign: 'right',
    border: '1px solid var(--mint-border, #ddd)',
    fontSize: '0.9em',
    color: 'var(--mint-text, inherit)'
  }}>
                Price
              </th>
            </tr>
          </thead>
          <tbody>
            {litActionConfigs.map((config, index) => {
    const priceComponentNum = Number(config.priceComponent);
    const priceMeasurementNum = Number(config.priceMeasurement);
    const componentName = LIT_ACTION_COMPONENT_NAMES[priceComponentNum] || `Component ${priceComponentNum}`;
    const measurementName = MEASUREMENT_NAMES[priceMeasurementNum] || '';
    const pricePerNode = weiToTokens(config.price, ethers);
    const priceInTokens = thresholdNodes ? pricePerNode * thresholdNodes : pricePerNode;
    const priceInUSD = litKeyPriceUSD ? priceInTokens * litKeyPriceUSD : null;
    return <tr key={index}>
                  <td style={{
      padding: '8px 10px',
      border: '1px solid var(--mint-border, #ddd)',
      fontSize: '0.9em'
    }}>
                    {componentName}
                    {measurementName && <span style={{
      color: 'var(--mint-text-secondary, #666)',
      marginLeft: '5px'
    }}>
                        {measurementName}
                      </span>}
                  </td>
                  <td style={{
      padding: '8px 10px',
      textAlign: 'right',
      border: '1px solid var(--mint-border, #ddd)',
      fontFamily: 'monospace',
      fontSize: '0.85em'
    }}>
                    {formatPrice(priceInTokens, priceInUSD)}
                  </td>
                </tr>;
  })}
          </tbody>
        </table>
      </div>
    </div>;
};

The following table shows the current pricing for Lit Protocol services on the **Naga Prod / Mainnet V1** network. Prices are displayed in both \$LITKEY tokens and USD (based on current market rates).

<Note>
  Most prices update dynamically based on network usage. The values shown below reflect real-time prices fetched from the blockchain. Note that PKP Minting cost is static and does not change with network utilization.
</Note>

## Understanding the Price Table

### Base vs Max Prices

* **Base Price**: The minimum price when network usage is low
* **Max Price**: The maximum price when the network is at full capacity
* **Current Price**: The actual price at this moment, which varies between base and max based on usage

### Product Types

* **PKP Sign**: Signing operations using your Programmable Key Pair
* **Decryption and Access Control**: Decrypting data and enforcing access control conditions
* **Lit Action**: Executing serverless JavaScript functions (pricing varies by component)
* **Sign Session Key**: Session-based signing operations
* **PKP Minting**: Creating a new Programmable Key Pair (static price, does not vary with network usage)

<PriceProvider component={CurrentPricesTable} />

### Lit Action Pricing Components

Lit Actions have multiple pricing components that are charged based on resource usage:

* **Base Amount**: Fixed cost per Lit Action execution.  You always pay this amount, regardless of the other components.
* **Runtime Length**: Cost per second of execution time.  Max execution time is 5 minutes.
* **Memory Usage**: Cost per megabyte of heap memory used.  Max memory usage is 256MB.
* **Code Length**: Cost based on the size of your Lit Action code.  Max code length is 16MB.
* **Response Length**: Cost based on the size of the response data.  Max response length is 1MB
* **Signatures**: Cost per signature generated.  Max signatures is 30.
* **Broadcasts**: Cost per `Lit.Actions.broadcastAndCollect` operation to share data between the nodes during action execution.  Max is 30.
* **Contract Calls**: Cost per smart contract call using `Lit.Actions.callContract`.  Max is 50.
* **Call Depth**: Cost per child Lit Action call stack depth when using `Lit.Actions.call`.  Max is 5.
* **Decrypts**: Cost per decryption operation using `Lit.Actions.decryptAndCombine` or `Lit.Actions.decryptToSingleNode`.
* **Fetches**: Cost per HTTP fetch request using `fetch()`.  Max is 75.

The total cost of a Lit Action is calculated by summing all applicable components based on your action's actual resource usage.

## Price Calculator

Enter your expected usage below to estimate the total cost. All prices reflect real-time network rates.

<PriceProvider component={PriceCalculator} />
