> ## Documentation Index
> Fetch the complete documentation index at: https://luminouslabs-cc5545c6-indexing-tokens.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# FAQ

> Frequently asked questions about light-token.

export const lightCreateAtaCode = ["// light-token create ATA", 'import { createAtaInterface } from "@lightprotocol/compressed-token";', "", "const ata = await createAtaInterface(", "  rpc,", "  payer,", "  mint,", "  owner", ");"].join("\n");

export const splCreateAtaCode = ["// SPL create ATA", 'import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token";', "", "const ata = await getOrCreateAssociatedTokenAccount(", "  connection,", "  payer,", "  mint,", "  owner", ");"].join("\n");

export const RentLifecycleVisualizer = () => {
  const [, setTime] = useState(0);
  const [lamports, setLamports] = useState(0);
  const [isRunning, setIsRunning] = useState(false);
  const [phase, setPhase] = useState("uninitialized");
  const [hasUserClicked, setHasUserClicked] = useState(false);
  const [showControls, setShowControls] = useState(false);
  const containerRef = useRef(null);
  const [isHighlighted, setIsHighlighted] = useState(false);
  const [activeArrows, setActiveArrows] = useState([]);
  const [activeLines, setActiveLines] = useState([]);
  const [isButtonPressed, setIsButtonPressed] = useState(false);
  const [flyingArrows, setFlyingArrows] = useState([]);
  const [floatingAmounts, setFloatingAmounts] = useState([]);
  const [resetCount, setResetCount] = useState(0);
  const [timelineStarted, setTimelineStarted] = useState(false);
  const LAMPORTS_PER_TICK = 60;
  const INITIAL_RENT = 6400;
  const TOPUP_LAMPORTS = 800;
  const TOPUP_THRESHOLD = 800;
  const COLD_THRESHOLD = 400;
  const GREY = {
    r: 161,
    g: 161,
    b: 170
  };
  const RED = {
    r: 227,
    g: 89,
    b: 48
  };
  const BLUE = {
    r: 120,
    g: 140,
    b: 180
  };
  const txLines = [{
    id: 0,
    x1: 5,
    y1: 20,
    x2: 50,
    y2: 50
  }, {
    id: 1,
    x1: 95,
    y1: 15,
    x2: 50,
    y2: 50
  }, {
    id: 2,
    x1: 0,
    y1: 50,
    x2: 50,
    y2: 50
  }, {
    id: 3,
    x1: 100,
    y1: 55,
    x2: 50,
    y2: 50
  }, {
    id: 4,
    x1: 10,
    y1: 85,
    x2: 50,
    y2: 50
  }, {
    id: 5,
    x1: 90,
    y1: 90,
    x2: 50,
    y2: 50
  }, {
    id: 6,
    x1: 50,
    y1: 0,
    x2: 50,
    y2: 50
  }];
  const interpolateColor = (c1, c2, t) => {
    const clamp = v => Math.max(0, Math.min(255, Math.round(v)));
    return {
      r: clamp(c1.r + (c2.r - c1.r) * t),
      g: clamp(c1.g + (c2.g - c1.g) * t),
      b: clamp(c1.b + (c2.b - c1.b) * t)
    };
  };
  const colorToRgba = (c, alpha = 1) => `rgba(${c.r}, ${c.g}, ${c.b}, ${alpha})`;
  const formatLamports = l => {
    if (l <= 0) return "0";
    const rounded = Math.round(l / 500) * 500;
    return `~${rounded.toLocaleString()}`;
  };
  const arrowIdRef = useRef(0);
  const flyingArrowIdRef = useRef(0);
  const floatingAmountIdRef = useRef(0);
  const triggerFlyingArrow = (amount, lineIndex) => {
    const id = flyingArrowIdRef.current++;
    setFlyingArrows(prev => [...prev, id]);
    setTimeout(() => {
      setFlyingArrows(prev => prev.filter(a => a !== id));
    }, 600);
    const amountId = floatingAmountIdRef.current++;
    const line = txLines[lineIndex] || txLines[0];
    setFloatingAmounts(prev => [...prev, {
      id: amountId,
      amount,
      x: line.x1,
      y: line.y1
    }]);
    setTimeout(() => {
      setFloatingAmounts(prev => prev.filter(a => a.id !== amountId));
    }, 800);
  };
  const triggerHighlight = () => {
    setIsHighlighted(true);
    setTimeout(() => setIsHighlighted(false), 500);
    const arrowId = arrowIdRef.current++;
    setActiveArrows(prev => [...prev, arrowId]);
    setTimeout(() => {
      setActiveArrows(prev => prev.filter(id => id !== arrowId));
    }, 500);
  };
  const triggerTransaction = lineIndex => {
    setActiveLines(prev => [...prev, {
      id: lineIndex,
      startTime: Date.now()
    }]);
    setTimeout(() => {
      setActiveLines(prev => prev.filter(l => l.id !== lineIndex));
    }, 500);
  };
  const txLineIndexRef = useRef(0);
  const lastLineIndexRef = useRef(0);
  const getNextLineIndex = () => {
    const index = txLineIndexRef.current;
    txLineIndexRef.current = (txLineIndexRef.current + 1) % txLines.length;
    lastLineIndexRef.current = index;
    return index;
  };
  const getAccountColor = () => {
    if (phase === "uninitialized") return GREY;
    if (phase === "cold") return BLUE;
    if (lamports > TOPUP_THRESHOLD) {
      return RED;
    } else if (lamports > COLD_THRESHOLD) {
      const t = 1 - (lamports - COLD_THRESHOLD) / (TOPUP_THRESHOLD - COLD_THRESHOLD);
      return interpolateColor(RED, BLUE, t);
    } else {
      return BLUE;
    }
  };
  const handleTopup = () => {
    triggerTransaction(getNextLineIndex());
    setIsButtonPressed(true);
    setTimeout(() => setIsButtonPressed(false), 200);
    if (phase === "uninitialized" || phase === "cold" || lamports === 0) {
      setLamports(INITIAL_RENT);
      setPhase("hot");
      triggerHighlight();
      triggerFlyingArrow(INITIAL_RENT, lastLineIndexRef.current);
      return;
    }
    if (lamports < TOPUP_THRESHOLD) {
      setLamports(l => l + TOPUP_LAMPORTS);
      triggerHighlight();
      triggerFlyingArrow(TOPUP_LAMPORTS, lastLineIndexRef.current);
    }
  };
  const txTimesRef = useRef([1.3, 2, 2.7, 3.3, 4, 4.7, 5.3, 6, 6.7, 7.3, 8, 8.7, 9.3, 10.1, 11.5, 12.8, 16, 16.7, 17.3, 18, 18.7, 19.3, 20, 20.7, 21.3, 22, 22.7, 23.3, 24, 24.7, 25.5, 26.8]);
  const handleReset = () => {
    setTime(0);
    setLamports(0);
    setPhase("uninitialized");
    setIsRunning(true);
    setTimelineStarted(false);
    setActiveLines([]);
    setActiveArrows([]);
    setFlyingArrows([]);
    setResetCount(c => c + 1);
    txLineIndexRef.current = 0;
    arrowIdRef.current = 0;
    flyingArrowIdRef.current = 0;
  };
  const handleDiamondClick = () => {
    if (!hasUserClicked) {
      setHasUserClicked(true);
      setIsRunning(true);
      setShowControls(true);
    }
  };
  useEffect(() => {
    if (!isRunning) return;
    const interval = setInterval(() => {
      setTime(t => {
        const newTime = t + 0.1;
        if (t < 1.0 && newTime >= 1.0) {
          setLamports(INITIAL_RENT);
          setPhase("hot");
          setTimelineStarted(true);
          triggerHighlight();
          triggerTransaction(getNextLineIndex());
        }
        txTimesRef.current.forEach(txTime => {
          if (newTime >= txTime && t < txTime) {
            triggerTransaction(getNextLineIndex());
            if (phase === "cold") {
              setLamports(INITIAL_RENT);
              setPhase("hot");
              triggerHighlight();
              triggerFlyingArrow(INITIAL_RENT, lastLineIndexRef.current);
            } else if (phase === "hot") {
              setLamports(currentLamports => {
                if (currentLamports > 0 && currentLamports < TOPUP_THRESHOLD) {
                  triggerHighlight();
                  triggerFlyingArrow(TOPUP_LAMPORTS, lastLineIndexRef.current);
                  return currentLamports + TOPUP_LAMPORTS;
                }
                return currentLamports;
              });
            }
          }
        });
        if ((phase === "hot" || phase === "cold") && newTime > 0.1) {
          setLamports(l => {
            const tickAmount = LAMPORTS_PER_TICK;
            const newLamports = Math.max(0, l - tickAmount);
            if (newLamports < COLD_THRESHOLD) {
              setPhase("cold");
            }
            return newLamports;
          });
        }
        if (newTime >= 29) {
          setPhase("uninitialized");
          setLamports(0);
          setHasUserClicked(false);
          setIsRunning(false);
          setShowControls(false);
          setTimelineStarted(false);
          txLineIndexRef.current = 0;
          return 0;
        }
        return newTime;
      });
    }, 100);
    return () => clearInterval(interval);
  }, [isRunning, phase]);
  const accountColor = getAccountColor();
  const generateDiamondDots = () => {
    const dots = [];
    const size = 5;
    const centerSize = 4;
    for (let row = -size; row <= size; row++) {
      const width = size - Math.abs(row);
      for (let col = -width; col <= width; col++) {
        const distFromCenter = Math.max(Math.abs(row), Math.abs(col));
        const fadeProgress = distFromCenter / size;
        const dotSize = Math.max(0.3, centerSize * Math.pow(1 - fadeProgress, 1.5));
        const opacity = Math.pow(1 - fadeProgress, 2.5);
        dots.push({
          x: 50 + col * 6,
          y: 50 + row * 6,
          size: dotSize,
          opacity
        });
      }
    }
    return dots;
  };
  const diamondDots = generateDiamondDots();
  const isLineActive = lineId => activeLines.some(l => l.id === lineId);
  return <div ref={containerRef} className="relative p-6 my-4 overflow-hidden" style={{
    fontFamily: "'Inter', 'IBM Plex Mono'"
  }}>
      {}
      <style>{`
        @keyframes scrollTimeline {
          from { transform: translateX(15rem); }
          to { transform: translateX(-95rem); }
        }
        .timeline-scroll {
          animation: scrollTimeline 29s linear infinite;
          animation-play-state: paused;
          animation-fill-mode: backwards;
        }
        .timeline-scroll-running {
          animation-play-state: running;
        }
        @keyframes bobbleMove {
          0% { offset-distance: 0%; opacity: 0; }
          10% { opacity: 1; }
          90% { opacity: 1; }
          100% { offset-distance: 100%; opacity: 0; }
        }
        .tx-bobble {
          animation: bobbleMove 0.5s ease-out forwards;
        }
        .btn-interactive {
          position: relative;
          overflow: hidden;
          background: rgba(120, 140, 180, 0.06);
          border: 1px solid rgba(120, 140, 180, 0.2);
          border-bottom-color: rgba(0, 0, 0, 0.08);
          box-shadow: 0 1px 2px rgba(0,0,0,0.05);
          color: rgb(0, 0, 0);
        }
        .dark .btn-interactive {
          background: rgba(120, 140, 180, 0.1);
          border: 1px solid rgba(120, 140, 180, 0.25);
          border-bottom-color: rgba(0, 0, 0, 0.2);
          box-shadow: 0 1px 2px rgba(0,0,0,0.1);
          color: rgb(255, 255, 255);
        }
        .btn-interactive:hover {
          background: rgba(120, 140, 180, 0.1);
          box-shadow: 0 2px 4px rgba(0,0,0,0.08);
        }
        .dark .btn-interactive:hover {
          background: rgba(120, 140, 180, 0.15);
          box-shadow: 0 2px 4px rgba(0,0,0,0.15);
        }
        .btn-interactive:active {
          background: rgba(120, 140, 180, 0.12);
          box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
          transform: translateY(0.5px);
        }
        .dark .btn-interactive:active {
          background: rgba(120, 140, 180, 0.18);
          box-shadow: inset 0 1px 2px rgba(0,0,0,0.2);
        }
        @keyframes arrowUp {
          0% { opacity: 0; transform: translateY(calc(-50% + 4px)); }
          20% { opacity: 1; }
          80% { opacity: 1; }
          100% { opacity: 0; transform: translateY(calc(-50% - 8px)); }
        }
        .arrow-up {
          animation: arrowUp 0.5s ease-out forwards;
        }
        @keyframes arrowFlyUp {
          0% { opacity: 1; transform: translateY(calc(-50% + 24px)); }
          80% { opacity: 1; }
          100% { opacity: 0; transform: translateY(calc(-50% - 8px)); }
        }
        .arrow-fly-up {
          animation: arrowFlyUp 0.4s ease-out forwards;
        }
        @keyframes amountFlyUp {
          0% { opacity: 1; transform: translateY(0); }
          70% { opacity: 1; }
          100% { opacity: 0; transform: translateY(-20px); }
        }
        .amount-fly-up {
          animation: amountFlyUp 0.8s ease-out forwards;
        }
      `}</style>

      {}
      <div className="relative flex items-center justify-center" style={{
    height: "11.5rem"
  }}>
        {}
        <svg className="absolute inset-0 w-full h-full" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" style={{
    filter: !hasUserClicked ? "blur(2px)" : "none",
    transition: "filter 0.3s ease"
  }}>
          {txLines.map(line => {
    const active = isLineActive(line.id);
    return <g key={line.id}>
                {}
                <line x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2} stroke={active ? "rgba(161, 161, 170, 0.5)" : "rgba(161, 161, 170, 0)"} strokeWidth={active ? 0.8 : 0} style={{
      transition: "stroke 0.15s, stroke-width 0.15s"
    }} />
                {}
                {active && <circle r="2" fill="rgba(161, 161, 170, 0.8)" style={{
      offsetPath: `path('M ${line.x1} ${line.y1} L ${line.x2} ${line.y2}')`
    }} className="tx-bobble" />}
              </g>;
  })}
          {}
          {floatingAmounts.map(({id, amount, x, y}) => <text key={id} x={x} y={y} className="amount-fly-up" style={{
    fill: "rgb(34, 197, 94)",
    fontSize: "8px",
    fontWeight: 700,
    fontFamily: "ui-monospace, monospace",
    textAnchor: "middle",
    dominantBaseline: "middle"
  }}>
              +{amount.toLocaleString()}
            </text>)}
        </svg>

        {}
        <div className="absolute inset-0 flex items-center justify-center" style={{
    maskImage: "linear-gradient(to right, transparent, black 15%, black 35%, transparent 45%, transparent 55%, black 65%, black 85%, transparent)",
    WebkitMaskImage: "linear-gradient(to right, transparent, black 15%, black 35%, transparent 45%, transparent 55%, black 65%, black 85%, transparent)",
    filter: !hasUserClicked ? "blur(2px)" : "none",
    transition: "filter 0.3s ease"
  }}>
          {}
          <div className="absolute inset-0 flex items-center overflow-hidden">
            <div key={resetCount} className={`flex items-center timeline-scroll ${timelineStarted ? "timeline-scroll-running" : ""}`} style={{
    gap: "5rem"
  }}>
              {[...Array(34).keys()].map(i => i * 3).concat([...Array(34).keys()].map(i => i * 3)).map((h, i) => <div key={i} className="flex flex-col items-center flex-shrink-0">
                    <span className="font-mono text-zinc-300 dark:text-white/20 mb-2" style={{
    fontSize: "1rem",
    opacity: timelineStarted ? 1 : 0,
    filter: timelineStarted ? "blur(0)" : "blur(8px)",
    transition: "opacity 0.5s ease, filter 0.5s ease"
  }}>
                      {h}h
                    </span>
                    <div className="w-px h-3 bg-zinc-200 dark:bg-white/20" />
                  </div>)}
            </div>
          </div>

          {}
          <div className="absolute left-0 right-0 h-px bg-gradient-to-r from-transparent via-zinc-300 dark:via-white/30 to-transparent" />
        </div>

        {}
        <div className="absolute z-10" onClick={handleDiamondClick} style={{
    left: "50%",
    top: "50%",
    transform: "translate(-50%, -50%)",
    cursor: !hasUserClicked ? "pointer" : "default",
    filter: activeLines.length > 0 ? "drop-shadow(0 0 25px rgba(227, 89, 48, 0.7)) drop-shadow(0 0 10px rgba(255, 150, 50, 0.8))" : "none",
    transition: "filter 0.15s ease"
  }}>
          <svg width="138" height="138" viewBox="0 0 100 100">
            {diamondDots.map((dot, i) => <circle key={i} cx={dot.x} cy={dot.y} r={dot.size} fill={colorToRgba(accountColor, dot.opacity * 0.7)} style={{
    transition: "fill 0.3s ease"
  }} />)}
          </svg>
          {}
          {!hasUserClicked && <div className="text-zinc-400 dark:text-white/40 text-center" style={{
    fontSize: "1.15rem",
    position: "absolute",
    top: "100%",
    left: "50%",
    transform: "translateX(-50%)",
    marginTop: "0.5rem",
    whiteSpace: "nowrap"
  }}>
              Press to see the Rent lifecycle over time!
            </div>}
        </div>
      </div>

      {}
      <div style={{
    opacity: showControls ? 1 : 0,
    filter: showControls ? "blur(0px)" : "blur(8px)",
    transition: "opacity 0.5s ease, filter 0.5s ease",
    pointerEvents: showControls ? "auto" : "none"
  }}>
        {}
        <div className="flex justify-center mt-4">
          {}
          <div className="relative flex items-center justify-end mr-2" style={{
    width: "1.5rem",
    height: "2.2rem"
  }}>
            {activeArrows.map(arrowId => <span key={arrowId} className="arrow-up absolute" style={{
    color: "rgb(34, 197, 94)",
    fontSize: "1.7rem",
    right: 0,
    top: "50%",
    transform: "translateY(-50%)",
    lineHeight: 1
  }}>
                ↑
              </span>)}
            {flyingArrows.map(id => <span key={id} className="arrow-fly-up absolute" style={{
    color: "rgb(34, 197, 94)",
    fontSize: "1.7rem",
    right: 0,
    top: "50%",
    lineHeight: 1
  }}>
                ↑
              </span>)}
          </div>
          <div className="text-center">
            <div style={{
    height: "2.2rem",
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
              <span className="font-mono text-zinc-700 dark:text-white/80 transition-all duration-150" style={{
    fontSize: isHighlighted ? "1.9rem" : "1.7rem",
    fontWeight: isHighlighted ? 700 : 500,
    transformOrigin: "center",
    transform: isHighlighted ? "scale(1.05)" : "scale(1)",
    fontVariantNumeric: "tabular-nums",
    minWidth: "6.5rem",
    textAlign: "right"
  }}>
                {formatLamports(lamports)}
              </span>
              <span className="text-zinc-400 dark:text-white/40 transition-all duration-150 ml-1" style={{
    fontSize: isHighlighted ? "1.45rem" : "1.15rem",
    fontWeight: isHighlighted ? 800 : 400
  }}>
                lamports
              </span>
            </div>
            <div className="text-zinc-500 dark:text-white/50 uppercase tracking-wide" style={{
    fontSize: "0.9rem"
  }}>
              Rent Balance
            </div>
          </div>
        </div>

        {}
        <div className="flex justify-center gap-4 mt-3">
          <button onClick={handleReset} className="font-medium rounded-lg border backdrop-blur-sm transition-all btn-interactive" style={{
    padding: "0.5rem 1rem",
    fontSize: "0.85rem"
  }}>
            Back to Start
          </button>
          <button onClick={handleTopup} className={`rounded-lg border-none backdrop-blur-sm transition-all ${isButtonPressed ? "font-bold" : "font-medium"}`} style={{
    padding: "0.5rem 1rem",
    fontSize: isButtonPressed ? "0.95rem" : "0.85rem",
    transform: isButtonPressed ? "scale(1.15)" : "scale(1)",
    background: "#0066ff",
    color: "#fff"
  }}>
            Send Tx
          </button>
        </div>
      </div>
    </div>;
};

export const CodeCompare = ({firstCode = "", secondCode = "", firstLabel = "Light Token", secondLabel = "SPL"}) => {
  const [sliderPercent, setSliderPercent] = useState(0);
  const [isDragging, setIsDragging] = useState(false);
  const [isAnimating, setIsAnimating] = useState(false);
  const containerRef = useRef(null);
  const animationRef = useRef(null);
  const isLightMode = sliderPercent > 50;
  const highlightCode = code => {
    let escaped = code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    const pattern = /(\/\/.*$)|(["'`])(?:(?!\2)[^\\]|\\.)*?\2|\b(const|let|var|await|async|import|from|export|return|if|else|function|class|new|throw|try|catch)\b|\.([a-zA-Z_][a-zA-Z0-9_]*)\b|\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/gm;
    return escaped.replace(pattern, (match, comment, stringQuote, keyword, property, func) => {
      if (comment) return `<span style="color:#6b7280;font-style:italic">${match}</span>`;
      if (stringQuote) return `<span style="color:#059669">${match}</span>`;
      if (keyword) return `<span style="color:#db2777">${match}</span>`;
      if (property) return `.<span style="color:#0891b2">${property}</span>`;
      if (func) return `<span style="color:#2563eb">${match}</span>`;
      return match;
    });
  };
  const animateTo = target => {
    if (animationRef.current) cancelAnimationFrame(animationRef.current);
    setIsAnimating(true);
    const start = sliderPercent;
    const startTime = performance.now();
    const duration = 400;
    const animate = currentTime => {
      const elapsed = currentTime - startTime;
      const progress = Math.min(elapsed / duration, 1);
      const eased = 1 - Math.pow(1 - progress, 3);
      const current = start + (target - start) * eased;
      setSliderPercent(current);
      if (progress < 1) {
        animationRef.current = requestAnimationFrame(animate);
      } else {
        setSliderPercent(target);
        setIsAnimating(false);
        animationRef.current = null;
      }
    };
    animationRef.current = requestAnimationFrame(animate);
  };
  const handleToggle = () => {
    animateTo(isLightMode ? 0 : 100);
  };
  const handleMouseDown = e => {
    if (isAnimating) {
      cancelAnimationFrame(animationRef.current);
      setIsAnimating(false);
    }
    e.preventDefault();
    setIsDragging(true);
  };
  const handleMouseUp = () => {
    setIsDragging(false);
  };
  const handleMouseMove = e => {
    if (!isDragging || !containerRef.current) return;
    const rect = containerRef.current.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const percent = Math.max(0, Math.min(100, x / rect.width * 100));
    setSliderPercent(percent);
  };
  const handleTouchMove = e => {
    if (!containerRef.current) return;
    if (isAnimating) {
      cancelAnimationFrame(animationRef.current);
      setIsAnimating(false);
    }
    const rect = containerRef.current.getBoundingClientRect();
    const x = e.touches[0].clientX - rect.left;
    const percent = Math.max(0, Math.min(100, x / rect.width * 100));
    setSliderPercent(percent);
  };
  const handleKeyDown = e => {
    if (e.key === "ArrowLeft") {
      setSliderPercent(p => Math.max(0, p - 5));
    } else if (e.key === "ArrowRight") {
      setSliderPercent(p => Math.min(100, p + 5));
    }
  };
  useEffect(() => {
    if (isDragging) {
      document.addEventListener("mousemove", handleMouseMove);
      document.addEventListener("mouseup", handleMouseUp);
      return () => {
        document.removeEventListener("mousemove", handleMouseMove);
        document.removeEventListener("mouseup", handleMouseUp);
      };
    }
  }, [isDragging]);
  useEffect(() => {
    return () => {
      if (animationRef.current) cancelAnimationFrame(animationRef.current);
    };
  }, []);
  return <>
      <div className="rounded-3xl not-prose mt-4 backdrop-blur-xl border overflow-hidden" style={{
    fontFamily: "Inter, sans-serif",
    borderColor: "#d4d4d8"
  }}>
        {}
        <div className="flex items-center justify-between px-4 py-3 border-b" style={{
    background: "linear-gradient(to bottom, #f8f9fa, #f1f3f4)",
    borderColor: "#e4e4e7"
  }}>
          <span className="text-sm font-medium" style={{
    color: "#52525b"
  }}>
            {isLightMode ? secondLabel : firstLabel}
          </span>

          {}
          <div onClick={handleToggle} style={{
    position: "relative",
    width: "56px",
    height: "28px",
    background: "#e0e0e0",
    borderRadius: "14px",
    boxShadow: "inset -2px -2px 4px #ffffff, inset 2px 2px 4px #b0b0b0",
    cursor: "pointer",
    transition: "background 0.3s ease, box-shadow 0.3s ease"
  }}>
            {}
            <div style={{
    position: "absolute",
    width: "24px",
    height: "24px",
    background: "linear-gradient(145deg, #f5f5f5, #e0e0e0)",
    borderRadius: "12px",
    top: "2px",
    left: isLightMode ? "30px" : "2px",
    boxShadow: "-2px -2px 4px #ffffff, 2px 2px 4px #b0b0b0",
    transition: "all 0.3s ease-in-out",
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
              {}
              <div style={{
    width: "6px",
    height: "6px",
    background: isLightMode ? "#0066ff" : "#999",
    borderRadius: "50%",
    boxShadow: isLightMode ? "0 0 8px 2px #0066ff" : "0 0 4px 1px rgba(0, 0, 0, 0.1)",
    transition: "all 0.3s ease-in-out"
  }} />
            </div>
          </div>
        </div>

        {}
        <div ref={containerRef} className="p-0" style={{
    cursor: isDragging ? "grabbing" : "default"
  }} onTouchMove={handleTouchMove} tabIndex={0} onKeyDown={handleKeyDown} role="slider" aria-valuenow={sliderPercent} aria-valuemin={0} aria-valuemax={100} aria-label="Code comparison slider">
          <div className="relative" style={{
    minHeight: "140px",
    overflowX: "auto"
  }}>
            <div style={{
    display: "grid"
  }}>
              {}
              <pre className="m-0 p-4 text-zinc-700 dark:text-white/80 bg-transparent" style={{
    gridArea: "1/1",
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
    fontSize: "13px",
    lineHeight: "1.6",
    whiteSpace: "pre",
    zIndex: 1
  }} dangerouslySetInnerHTML={{
    __html: highlightCode(firstCode)
  }} />

              {}
              <pre className="m-0 p-4 text-zinc-700 dark:text-white/80 bg-white dark:bg-zinc-900" style={{
    gridArea: "1/1",
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
    fontSize: "13px",
    lineHeight: "1.6",
    whiteSpace: "pre",
    zIndex: 2,
    clipPath: `inset(0 ${100 - sliderPercent}% 0 0)`
  }} dangerouslySetInnerHTML={{
    __html: highlightCode(secondCode)
  }} />
            </div>

            {}
            <div className="absolute top-0 bottom-0 flex items-center justify-center pointer-events-none" style={{
    left: `${sliderPercent}%`,
    transform: "translateX(-50%)",
    zIndex: 30
  }}>
              <div className="absolute top-0 bottom-0 w-px bg-zinc-400 dark:bg-white/30" />

              <div className="absolute top-0 bottom-0" style={{
    right: "50%",
    width: "80px",
    background: "linear-gradient(to left, rgba(0, 102, 255, 0.15) 0%, transparent 100%)"
  }} />

              {}
              <div onMouseDown={handleMouseDown} className="pointer-events-auto cursor-grab flex items-center justify-center gap-px transition-transform" style={{
    width: "20px",
    height: "32px",
    borderRadius: "4px",
    background: "#f8fafc",
    border: "1px solid #d1d5db",
    boxShadow: "0 1px 2px rgba(0,0,0,0.05)",
    transform: isDragging ? "scale(1.08)" : "scale(1)"
  }}>
                <div className="flex flex-col gap-0.5">
                  {[0, 1, 2].map(i => <div key={i} style={{
    width: "3px",
    height: "3px",
    borderRadius: "50%",
    background: "#0066ff"
  }} />)}
                </div>
                <div className="flex flex-col gap-0.5">
                  {[0, 1, 2].map(i => <div key={i} style={{
    width: "3px",
    height: "3px",
    borderRadius: "50%",
    background: "#0066ff"
  }} />)}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </>;
};

#### What is light-token?

Light token is a high-performance token standard that is functionally equivalent to SPL, but stores mint and token accounts more efficiently. This reduces account creation cost while being more CU efficient than SPL on hot paths.

**Creation Cost**

|                   |     Light-Token |  SPL-Token |
| :---------------- | --------------: | ---------: |
| **Mint Account**  | **0.00001 SOL** | 0.0015 SOL |
| **Token Account** | **0.00001 SOL** |  0.002 SOL |

**CU Performance**

|                          | Light-Token | SPL-Token |
| :----------------------- | ----------: | --------: |
| **ATA Creation**         |   **4,348** |    14,194 |
| **Transfer**             |     **312** |     4,645 |
| **Transfer** (rent-free) |   **1,885** |     4,645 |

#### Can I start using the Light Token Standard?

Yes! Light Token is deployed on devnet — start integrating today with our [Quickstart](/light-token/quickstart) and [Toolkits](/light-token/toolkits/overview).

For production on mainnet, use [Compressed Tokens V1](/compressed-tokens/overview), which are live and supported by leading wallets such as Phantom and Backpack.

#### Do I need to change my client code significantly?

No. The `light-token-sdk` methods are a superset of the SPL-token API.
Find examples below.

<CodeCompare firstCode={splCreateAtaCode} secondCode={lightCreateAtaCode} firstLabel="SPL" secondLabel="light-token" />

<table>
  <thead>
    <tr>
      <th style={{ width: "15%" }} />

      <th>Light</th>
      <th>SPL</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>**Get/Create ATA**</td>
      <td>getOrCreateAtaInterface()</td>
      <td>getOrCreateAssociatedTokenAccount()</td>
    </tr>

    <tr>
      <td>**Derive ATA**</td>
      <td>getAssociatedTokenAddressInterface()</td>
      <td>getAssociatedTokenAddress()</td>
    </tr>

    <tr>
      <td>**Transfer**</td>
      <td>transferInterface()</td>
      <td>transferChecked()</td>
    </tr>

    <tr>
      <td>**Get Balance**</td>
      <td>getAtaInterface()</td>
      <td>getAccount()</td>
    </tr>
  </tbody>
</table>

***

#### Can light-token accounts hold SPL tokens?

Yes, light-token accounts can hold tokens from light, SPL, or Token 2022 mints.

SPL tokens can be deposited into light-token accounts and withdrawn back to SPL token accounts via the `transferInterface` method.

#### Do light-token accounts require rent?

The token standard pays rent-exemption cost for you. To prevent griefing, "rent" is paid over time to keep an account in memory. This is dealt with under the hood in a way that doesn't disrupt the UX of what your users are used to with SPL-token.

1. The Light Token Program pays the rent-exemption cost for the account.
2. Transaction fee payers bump a virtual rent balance when writing to the account, which keeps the account "hot".
3. "Cold" accounts virtual rent balance below threshold (eg 24h without write bump) get auto-compressed.
4. The cold account's state is cryptographically preserved on the Solana ledger.
   Users can load a cold account into hot state in-flight when using the account
   again.

<RentLifecycleVisualizer />

#### What happens if my light-token account runs out of rent?

The account is automatically compressed.
Your tokens are cryptographically preserved as a compressed token account (rent-free).
The account is loaded into hot account state in-flight when someone interacts with it again.

#### Does light-token support extensions?

Extensions are under development. Additional extensions can be requested.

Coming soon:

* MetadataPointer
* TokenMetadata
* InterestBearingConfig
* GroupPointer
* GroupMemberPointer
* TokenGroup
* TokenGroupMember
* MintCloseAuthority
* TransferFeeConfig
* DefaultAccountState
* PermanentDelegate
* TransferHook
* Pausable
* ConfidentialTransferMint
* ConfidentialTransferFeeConfig
* ConfidentialMintBurn

#### What is the difference between light-token and compressed token?

* **light-token**: Solana account that holds token balances of light-mints, SPL or Token 22 mints.
* **Compressed token**: Compressed account storing token data. Rent-free, for storage and distribution.

#### I don't see the question I want answered

DM us [@lightprotocol on X (Twitter)](http://x.com/lightprotocol) or [Discord](https://discord.com/invite/rpddh53TeG).

### Get Started

<CardGroup cols={2}>
  <Card title="Toolkits" icon="toolbox" href="/light-token/toolkits">
    Guides for dedicated use cases
  </Card>

  <Card title="Cookbook" icon="book" href="/light-token/cookbook">
    Step-by-step recipes
  </Card>
</CardGroup>
