> ## Documentation Index
> Fetch the complete documentation index at: https://www.zkcompression.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FAQ

> Frequently asked questions about light token, PDA accounts, and use cases.

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

export const splCreateAtaCode = ['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", language = "javascript"}) => {
  const [sliderPercent, setSliderPercent] = useState(100);
  const [isDragging, setIsDragging] = useState(false);
  const [isAnimating, setIsAnimating] = useState(false);
  const [copied, setCopied] = useState(false);
  const containerRef = useRef(null);
  const animationRef = useRef(null);
  const firstPreRef = useRef(null);
  const secondPreRef = useRef(null);
  const [containerHeight, setContainerHeight] = useState(null);
  const showingFirst = sliderPercent > 50;
  const handleCopy = async () => {
    const codeToCopy = showingFirst ? firstCode : secondCode;
    await navigator.clipboard.writeText(codeToCopy);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };
  const highlightCode = code => {
    let escaped = code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    if (language === "rust") {
      const rustPattern = /(\/\/.*$)|(["'])(?:(?!\2)[^\\]|\\.)*?\2|\b(use|let|mut|pub|fn|struct|impl|enum|mod|const|static|trait|type|where|for|in|if|else|match|loop|while|return|self|Self|true|false|Some|None|Ok|Err|Result|Option|vec!)\b|::([a-zA-Z_][a-zA-Z0-9_]*)|&amp;([a-zA-Z_][a-zA-Z0-9_]*)|\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()|(\?)/gm;
      return escaped.replace(rustPattern, (match, comment, stringQuote, keyword, pathSegment, reference, func, questionMark) => {
        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 (pathSegment) return `::<span style="color:#0891b2">${pathSegment}</span>`;
        if (reference) return `&amp;<span style="color:#6366f1">${reference}</span>`;
        if (func) return `<span style="color:#2563eb">${match}</span>`;
        if (questionMark) return `<span style="color:#db2777">?</span>`;
        return match;
      });
    }
    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(showingFirst ? 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);
    };
  }, []);
  useEffect(() => {
    const activeRef = showingFirst ? firstPreRef : secondPreRef;
    if (activeRef.current) {
      setContainerHeight(activeRef.current.scrollHeight);
    }
  }, [showingFirst]);
  return <>
      <div className="rounded-3xl not-prose mt-4 backdrop-blur-xl border overflow-hidden border-zinc-300 dark:border-zinc-700" style={{
    fontFamily: "Inter, sans-serif"
  }}>
        {}
        <div className="flex items-center justify-between px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 bg-gray-50 dark:bg-zinc-900">
          <span className="text-sm font-medium text-zinc-600 dark:text-zinc-300">
            {showingFirst ? firstLabel : secondLabel}
          </span>

          <div className="flex items-center gap-3">
            {}
            <button onClick={handleCopy} className="p-1.5 rounded hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors text-zinc-500 dark:text-zinc-400" title="Copy code" style={{
    background: "transparent",
    border: "none",
    cursor: "pointer"
  }}>
              {copied ? <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#22c55e" strokeWidth="2">
                  <path d="M20 6L9 17l-5-5" />
                </svg> : <svg width="18" height="18" viewBox="0 0 18 18" fill="none">
                  <path d="M14.25 5.25H7.25C6.14543 5.25 5.25 6.14543 5.25 7.25V14.25C5.25 15.3546 6.14543 16.25 7.25 16.25H14.25C15.3546 16.25 16.25 15.3546 16.25 14.25V7.25C16.25 6.14543 15.3546 5.25 14.25 5.25Z" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                  <path d="M2.80103 11.998L1.77203 5.07397C1.61003 3.98097 2.36403 2.96397 3.45603 2.80197L10.38 1.77297C11.313 1.63397 12.19 2.16297 12.528 3.00097" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
                </svg>}
            </button>

            {}
            <div onClick={handleToggle} className="bg-zinc-200 dark:bg-zinc-600" style={{
    position: "relative",
    width: "56px",
    height: "28px",
    borderRadius: "14px",
    boxShadow: "inset -2px -2px 4px rgba(255,255,255,0.3), inset 2px 2px 4px rgba(0,0,0,0.1)",
    cursor: "pointer",
    transition: "all 0.3s ease"
  }}>
              {}
              <div className="bg-white dark:bg-zinc-300" style={{
    position: "absolute",
    width: "24px",
    height: "24px",
    borderRadius: "12px",
    top: "2px",
    left: showingFirst ? "30px" : "2px",
    boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
    transition: "all 0.3s ease-in-out",
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
                {}
                <div style={{
    width: "6px",
    height: "6px",
    background: showingFirst ? "#0066ff" : "#999",
    borderRadius: "50%",
    boxShadow: showingFirst ? "0 0 5px 1px rgba(0, 102, 255, 0.6)" : "0 0 4px 1px rgba(0, 0, 0, 0.1)",
    transition: "all 0.3s ease-in-out"
  }} />
              </div>
            </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",
    overflow: "hidden",
    height: containerHeight ? `${containerHeight}px` : "auto",
    transition: "height 0.3s ease"
  }}>
            <div style={{
    position: "relative"
  }}>
              {}
              <pre ref={secondPreRef} className="m-0 p-4 text-zinc-700 dark:text-white/80 bg-transparent" style={{
    position: showingFirst ? "absolute" : "relative",
    top: 0,
    left: 0,
    right: 0,
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
    fontSize: "13px",
    lineHeight: "1.6",
    whiteSpace: "pre",
    zIndex: 1
  }} dangerouslySetInnerHTML={{
    __html: highlightCode(secondCode)
  }} />

              {}
              <pre ref={firstPreRef} className="m-0 p-4 text-zinc-700 dark:text-white/80 bg-white dark:bg-zinc-900" style={{
    position: showingFirst ? "relative" : "absolute",
    top: 0,
    left: 0,
    right: 0,
    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(firstCode)
  }} />
            </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: "60px",
    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>
    </>;
};

## Rent Sponsorship

<Accordion title="How does rent-exemption sponsorship work ?">
  Rent sponsorship is a built-in feature of the Light SDK’s that sponsors rent-exemption for all account types to reduce creation cost: mints, token accounts, and PDAs.
  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.

  | Account Creation Cost | Light              | Standard Solana |
  | :-------------------- | :----------------- | :-------------- |
  | **Mint account**      | **\~0.000091 SOL** | \~0.0015 SOL    |
  | **Token account**     | **0.000017 SOL**   | \~0.0029 SOL    |
  | **PDA (100-byte)**    | **\~0.000012 SOL** | \~0.0016 SOL    |

  **Rent-exemption: paid by a rent sponsor PDA.**

  **Top-ups: paid by the fee payer.**

  The `feePayer` on the transaction bumps a small virtual rent balance (766 lamports by default)
  on each write to keep the account active (hot balance).
  Set your application as the fee payer so users never interact with SOL.

  **Hot-Cold Lifecycle of Accounts.**

  Accounts get auto-compressed (cold balance) when the virtual rent balance goes below a threshold (eg 24h without write bump).
  The cold account's state is cryptographically preserved on the Solana ledger.
  Users only interact with hot accounts and load the cold balance in-flight when using the account again.

  <div className="block dark:hidden">
    <Frame>
      <img src="https://mintcdn.com/luminouslabs-cc5545c6/c8IlA_YQ_pxDvBKq/images/account-lifecycle.png?fit=max&auto=format&n=c8IlA_YQ_pxDvBKq&q=85&s=279bbee42bce24f419ba8d8c229f3b6e" alt="Account lifecycle" width="1199" height="805" data-path="images/account-lifecycle.png" />
    </Frame>
  </div>

  <div className="hidden dark:block">
    <Frame>
      <img src="https://mintcdn.com/luminouslabs-cc5545c6/c8IlA_YQ_pxDvBKq/images/account-lifecycle-dark.png?fit=max&auto=format&n=c8IlA_YQ_pxDvBKq&q=85&s=b41a6fc1f9c7a9d7df2dbc3e0b03639c" alt="Account lifecycle" width="1182" height="788" data-path="images/account-lifecycle-dark.png" />
    </Frame>
  </div>
</Accordion>

<Accordion title="How can I make transactions gasless for my users?">
  Set the `payer` parameter to the sponsor's public key on any Light Token instruction. The sponsor pays SOL for rent top-ups and transaction fees while the user only signs to authorize the transfer.

  ```typescript theme={null}
  const ix = createLightTokenTransferInstruction(
    senderAta,
    recipientAta,
    sender.publicKey,
    amount,
    sponsor.publicKey, // sponsor pays rent top-ups and transaction fees
  );

  await sendAndConfirmTransaction(rpc, tx, [sponsor, sender]);
  ```

  <Card title="Gasless transactions guide" icon="chevron-right" color="#0066ff" href="/light-token/wallets/gasless-transactions" horizontal />
</Accordion>

## Light Token Program

<Accordion title="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**

  | Creation Cost     |      Light Token | SPL / Token 2022 |
  | :---------------- | ---------------: | ---------------: |
  | **Mint Account**  | **0.000091 SOL** |       0.0015 SOL |
  | **Token Account** | **0.000017 SOL** |       0.0029 SOL |

  **CU Performance**

  | CU Performance           | Light Token | SPL-Token |
  | :----------------------- | ----------: | --------: |
  | **ATA Creation**         |   **4,348** |    14,194 |
  | **Transfer**             |     **312** |     4,645 |
  | **Transfer** (rent-free) |   **1,885** |     4,645 |
</Accordion>

<Accordion title="Can I start using the Light Token Standard?">
  Yes! Light Token is live on Solana mainnet. Start integrating with the [Quickstart](/light-token/quickstart) and [Toolkits](/light-token/welcome).

  For token distribution use cases (airdrops, claims), see [Compressed Tokens](/resources/legacy-compressed-tokens), supported by leading wallets such as Phantom and Backpack.
</Accordion>

<Accordion title="Do I need to change my client code significantly?">
  No. The `light-token-sdk` methods are a superset of the SPL-token API — every SPL operation (transfer, approve, revoke, freeze, thaw, burn, close) plus unified balance aggregation, automatic load/decompress, wrap/unwrap, and cross-program dispatch. See "What does 'superset of the SPL-token API' mean?" below for details.

  <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>

  <Card title="View complete Solana to Light Reference" icon="code-compare" href="/api-reference/solana-to-light-comparison">
    Side-by-side mapping of every Light Token instruction against its SPL/Solana equivalent.
  </Card>
</Accordion>

<Accordion title="What does 'superset of the SPL-token API' mean?">
  The Light Token SDK covers every SPL Token operation and adds extra capabilities:

  <table>
    <thead>
      <tr>
        <th style={{ width: "25%" }}>Category</th>
        <th>What it does</th>
      </tr>
    </thead>

    <tbody>
      <tr>
        <td>**Cross-program dispatch**</td>
        <td>`Interface` methods (e.g., `transferInterface`) auto-detect the token program and dispatch to SPL, Token 2022, or Light Token.</td>
      </tr>

      <tr>
        <td>**Unified balance**</td>
        <td>`getAtaInterface` returns a unified balance for a given mint, aggregating Light Token (hot + cold), SPL, and Token 2022 sources.</td>
      </tr>

      <tr>
        <td>**Wrap / Unwrap**</td>
        <td>For interoperability with applications that don't support Light Token yet, you can wrap / unwrap SPL or Token 2022 tokens into Light Token associated token accounts and back.</td>
      </tr>
    </tbody>
  </table>

  <Card title="View complete Solana to Light reference" icon="code-compare" href="/api-reference/solana-to-light-comparison">
    Side-by-side mapping of every Light Token instruction against its SPL/Solana equivalent.
  </Card>
</Accordion>

<Accordion title="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.
</Accordion>

<Accordion title="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. A rent sponsor PDA by Light Protocol 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 />
</Accordion>

<Accordion title="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.
</Accordion>

<Accordion title="Does light-token support extensions?">
  Light Token supports 16 Token-2022 extensions. Some have restrictions.

  | Extension                         | Restriction                                   | Description                                                                               | Links                                                                                                                                                                                                           |
  | --------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | **MetadataPointer**               | -                                             | Points a mint to the account that stores its metadata.                                    | [Solana Docs](https://solana.com/developers/guides/token-extensions/metadata-pointer) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts)  |
  | **TokenMetadata**                 | -                                             | Stores token name, symbol, and URI directly on the mint.                                  | [Solana Docs](https://solana.com/developers/guides/token-extensions/metadata-pointer) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/metadata-and-metadata-pointer.ts)  |
  | **TransferFeeConfig**             | Fees must be zero                             | Withholds a percentage of each transfer as a fee.                                         | [Solana Docs](https://solana.com/developers/guides/token-extensions/transfer-fee) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-fees.ts)                      |
  | **TransferHook**                  | `program_id` must be nil                      | Invokes a custom program on every transfer via CPI.                                       | [Solana Docs](https://solana.com/developers/guides/token-extensions/transfer-hook) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/transfer-hook.ts)                     |
  | **InterestBearingConfig**         | -                                             | Displays a UI-adjusted balance that accrues interest over time.                           | [Solana Docs](https://solana.com/developers/guides/token-extensions/interest-bearing-tokens) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/interest-bearing-tokens.ts) |
  | **DefaultAccountState**           | Set `compression_only` flag on token accounts | Sets the initial state (e.g., frozen) for newly created token accounts.                   | [Solana Docs](https://solana.com/developers/guides/token-extensions/default-account-state) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/default-account-state.ts)     |
  | **PermanentDelegate**             | Set `compression_only` flag on token accounts | Grants an authority unrestricted transfer and burn rights over all accounts for the mint. | [Solana Docs](https://solana.com/developers/guides/token-extensions/permanent-delegate) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/permanent-delegate.ts)           |
  | **MintCloseAuthority**            | Set `compression_only` flag on token accounts | Allows a designated authority to close a mint account.                                    | [Solana Docs](https://solana.com/developers/guides/token-extensions/mint-close-authority) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/close-mint.ts)                 |
  | **GroupPointer**                  | -                                             | Points a mint to the account that stores group configuration.                             | [Solana Docs](https://solana.com/docs/tokens/extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts)                       |
  | **GroupMemberPointer**            | -                                             | Points a mint to the account that stores group member configuration.                      | [Solana Docs](https://solana.com/docs/tokens/extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts)                       |
  | **TokenGroup**                    | -                                             | Stores group configuration directly on the mint (e.g., NFT collections).                  | [Solana Docs](https://solana.com/docs/tokens/extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts)                       |
  | **TokenGroupMember**              | -                                             | Stores group member configuration directly on the mint.                                   | [Solana Docs](https://solana.com/docs/tokens/extensions/group-member) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/token-groups-and-members.ts)                       |
  | **Pausable**                      | Set `compression_only` flag on token accounts | Allows an authority to pause all minting, burning, and transfers.                         | [Solana Docs](https://solana.com/docs/tokens/extensions/pausable) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/pausable-mint.ts)                                      |
  | **ConfidentialTransferMint**      | Initialized but not enabled                   | Configures auditor keys for confidential (encrypted) transfers.                           | [Solana Docs](https://www.solana-program.com/docs/confidential-balances) · [Example](https://github.com/Lightprotocol/examples-light-token/blob/main/extensions/confidential-transfer.ts)                       |
  | **ConfidentialTransferFeeConfig** | Initialized but not enabled                   | Encrypts withheld transfer fees under an auditor's public key.                            | [Solana Docs](https://www.solana-program.com/docs/confidential-balances)                                                                                                                                        |
  | **ConfidentialMintBurn**          | Initialized but not enabled                   | Allows minting and burning of tokens with encrypted amounts.                              | [Solana Docs](https://www.solana-program.com/docs/confidential-balances)                                                                                                                                        |

  <Card title="View all supported extensions" icon="chevron-right" color="#0066ff" href="/light-token/extensions/overview" horizontal />

  Additional extensions can be requested.
</Accordion>

<Accordion title="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.
</Accordion>

***

## PDA Accounts

<Accordion title="What is a Light-PDA?">
  A standard Solana PDA with sponsored rent-exemption. Seeds, bump derivation, and `invoke_signed` work the same way. Your instruction handlers for reads, updates, and closes don't change.

  | Creation Cost        |  Regular PDA |      Light-PDA |
  | :------------------- | -----------: | -------------: |
  | **100-byte account** | \~0.0016 SOL | \~0.000012 SOL |
</Accordion>

<Accordion title="What is a compressed PDA?">
  A compressed account with a derived address. Programs invoke the Light System program instead of the System program to create and update compressed accounts. Compressed PDAs are always compressed and require a validity proof for every read and write.

  | Creation Cost        |  Regular PDA | Compressed PDA |
  | :------------------- | -----------: | -------------: |
  | **100-byte account** | \~0.0016 SOL |   0.000015 SOL |
</Accordion>

<Accordion title="When should I use Light-PDA vs compressed PDA?">
  |                     | Light-PDA                                                        | Compressed PDA                                                 |
  | :------------------ | :--------------------------------------------------------------- | :------------------------------------------------------------- |
  | **Storage**         | On-chain; auto-compresses when inactive                          | Always compressed                                              |
  | **Validity proof**  | Not required                                                     | Required for every read and write                              |
  | **Program changes** | Minimal changes. Leaves program logic mostly untouched.          | Custom Logic                                                   |
  | **Best for**        | Shared state: DeFi pools, vaults, config, program-owned accounts | Per-user state: profiles, credentials, DePIN nodes, nullifiers |

  <Card title="PDA accounts overview" icon="chevron-right" color="#0066ff" href="/pda/overview" horizontal />
</Accordion>

<Accordion title="Do I need to rewrite my Anchor program to use Light-PDA?">
  No. Add `compression_info: CompressionInfo` to your state struct, derive `LightAccount` and `LightAccounts`, and add `#[light_program]` above `#[program]`. Your instruction logic for reads, updates, and closes stays the same. The client prepends a load instruction if the account is cold.

  <Card title="Light-PDA guide" icon="chevron-right" color="#0066ff" href="/pda/light-pda/overview" horizontal />
</Accordion>

<Accordion title="Do Light-PDAs require rent?">
  The SDK sponsors rent-exemption for your Light-PDAs. After extended inactivity, the account compresses to cold state and the rent-exempt lamports return to the rent sponsor. The common path (hot accounts) has no extra overhead.

  1. A rent sponsor PDA by Light Protocol 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.
</Accordion>

<Accordion title="What happens if my Light-PDA runs out of rent?">
  The account data is cryptographically preserved in compressed state. The client prepends a load instruction when someone interacts with it again — your program code doesn't change. Reads, updates, and closes work the same way regardless of whether the account is hot or cold.
</Accordion>

***

## 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).

<Card title="Learn Core Concepts" icon="graduation-cap" href="/learn/light-token-standard" />
