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

# Market states

> Understand each market status and the actions available to position holders.

export const DocsFlowEmbed = ({flowId, title, height = 760, mobileHeight, baseUrl}) => {
  const localWebOrigin = "http://localhost:3004";
  const productionWebOrigin = "https://www.flew.live";
  const getTheme = () => {
    if (typeof document === "undefined") return "light";
    const root = document.documentElement;
    const explicitTheme = root.dataset.theme || root.dataset.colorMode;
    if (explicitTheme === "dark" || root.classList.contains("dark")) {
      return "dark";
    }
    if (explicitTheme === "light") return "light";
    return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  };
  const getDefaultOrigin = () => {
    if (typeof window === "undefined") return productionWebOrigin;
    const isLocalDocs = ["localhost", "127.0.0.1", "::1"].includes(window.location.hostname);
    return isLocalDocs ? localWebOrigin : productionWebOrigin;
  };
  const iframeRef = useRef(null);
  const [theme, setTheme] = useState("light");
  const [isMobile, setIsMobile] = useState(false);
  const [isLoaded, setIsLoaded] = useState(false);
  const [hasTimedOut, setHasTimedOut] = useState(false);
  const [attempt, setAttempt] = useState(0);
  const [detectedOrigin, setDetectedOrigin] = useState(productionWebOrigin);
  const origin = useMemo(() => {
    const value = baseUrl || detectedOrigin;
    try {
      return new URL(value).origin;
    } catch {
      return detectedOrigin;
    }
  }, [baseUrl, detectedOrigin]);
  const source = useMemo(() => {
    const safeFlowId = String(flowId || "").replace(/[^a-z0-9-]/gi, "");
    const params = new URLSearchParams({
      embed: "1",
      theme: "system",
      attempt: String(attempt)
    });
    return `${origin}/docs-flow/${safeFlowId}?${params.toString()}`;
  }, [attempt, flowId, origin]);
  const postTheme = useCallback(nextTheme => {
    iframeRef.current?.contentWindow?.postMessage({
      type: "flew-docs-theme",
      theme: nextTheme
    }, origin);
  }, [origin]);
  useEffect(() => {
    setDetectedOrigin(getDefaultOrigin());
    setTheme(getTheme());
    const media = window.matchMedia?.("(prefers-color-scheme: dark)");
    const mobileMedia = window.matchMedia?.("(max-width: 640px)");
    const updateTheme = () => setTheme(getTheme());
    const updateMobile = () => setIsMobile(Boolean(mobileMedia?.matches));
    const observer = new MutationObserver(updateTheme);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class", "data-theme", "data-color-mode"]
    });
    updateMobile();
    media?.addEventListener?.("change", updateTheme);
    mobileMedia?.addEventListener?.("change", updateMobile);
    return () => {
      observer.disconnect();
      media?.removeEventListener?.("change", updateTheme);
      mobileMedia?.removeEventListener?.("change", updateMobile);
    };
  }, []);
  useEffect(() => {
    postTheme(theme);
  }, [postTheme, theme]);
  useEffect(() => {
    if (isLoaded) return undefined;
    const timeout = window.setTimeout(() => setHasTimedOut(true), 12000);
    return () => window.clearTimeout(timeout);
  }, [attempt, isLoaded]);
  const retry = () => {
    setIsLoaded(false);
    setHasTimedOut(false);
    setAttempt(value => value + 1);
  };
  const handleLoad = () => {
    setIsLoaded(true);
    setHasTimedOut(false);
    postTheme(theme);
  };
  const accessibleTitle = title || "Flew user flow";
  const effectiveMobileHeight = mobileHeight || height;
  const frameHeight = isMobile ? effectiveMobileHeight : height;
  return <figure className="flew-docs-flow not-prose" style={{
    "--flew-flow-height": `${height}px`,
    "--flew-flow-mobile-height": `${effectiveMobileHeight}px`
  }} aria-label={accessibleTitle}>
      <div className="flew-docs-flow__viewport">
        {!isLoaded && !hasTimedOut && <div className="flew-docs-flow__status" role="status" aria-live="polite">
            <span className="flew-docs-flow__spinner" aria-hidden="true" />
            <span>Loading interactive diagram…</span>
          </div>}

        {hasTimedOut && !isLoaded && <div className="flew-docs-flow__status" role="alert">
            <strong>
              The interactive diagram is taking longer than expected.
            </strong>
            <span>You can try again or open it directly in Flew.</span>
            <div className="flew-docs-flow__actions">
              <button type="button" onClick={retry}>
                Try again
              </button>
              <a href={source} target="_blank" rel="noreferrer">
                Open diagram
              </a>
            </div>
          </div>}

        <iframe ref={iframeRef} key={attempt} className="flew-docs-flow__frame" src={source} title={accessibleTitle} style={{
    height: `${frameHeight}px`,
    minHeight: `${frameHeight}px`
  }} loading="lazy" onLoad={handleLoad} onError={() => setHasTimedOut(true)} allow="fullscreen" />
      </div>

      <figcaption className="flew-docs-flow__caption">
        <span>
          Use the controls to zoom or fit the view.
        </span>
        <a href={source} target="_blank" rel="noreferrer">
          Open full screen
        </a>
      </figcaption>
    </figure>;
};

Flew combines the market's on-chain state with Solana cluster time to display its effective lifecycle status.

## Active

The market is open and has not reached its closing time.

You can:

* Place a YES or NO position if you do not already have one
* Exit an eligible open position after the minimum holding period

Live YES and NO pool totals remain encrypted during this phase. Flew does not display live pool odds.

## Awaiting resolution

The closing time has passed, but the resolution deadline has not.

* New positions are closed.
* Early exit is closed.
* Existing position holders wait for a manual outcome or verified Switchboard resolution.

No position-holder action is available during this phase.

## Refunds available

The market missed its resolution deadline. This can happen to either a manual or Switchboard market.

If you hold an unclaimed position, click **Claim Refund** before the refund deadline. The refund returns your net position amount after the original placement fee.

## Resolved

The outcome and aggregate YES and NO pool totals have been finalized.

* Winning positions can click **Claim Payout** during the claim window.
* Losing positions have no payout.
* A winning payout includes the net position plus its proportional share of the losing pool.

### Claim period expired

After the claim deadline, the market remains under the **Resolved** filter, but the market page displays **Claim Period Expired**. Unclaimed positions can no longer receive a payout.

## Expired

An unresolved market becomes expired after its refund window closes.

Position holders can no longer claim refunds or take any other settlement action.

## Lifecycle diagram

<DocsFlowEmbed flowId="market-lifecycle" title="Market lifecycle user flow" height={800} mobileHeight={900} />

| Displayed status         | Position-holder action                                       | What happens next                                                        |
| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------------------ |
| **Active**               | Place one position, or exit early when eligible              | Closing time moves the market to **Awaiting Resolution**                 |
| **Awaiting Resolution**  | No action                                                    | A finalized outcome resolves the market; a missed deadline opens refunds |
| **Resolved**             | Winners can click **Claim Payout** before the claim deadline | Wallet approval and Arcium finalization settle the position              |
| **Refunds Available**    | Click **Claim Refund** before the refund deadline            | The net position amount returns after Arcium finalization                |
| **Claim Period Expired** | No payout action                                             | The market remains grouped under the **Resolved** filter                 |
| **Expired**              | No refund or settlement action                               | The unresolved-market refund path has ended                              |

A losing position has no payout action in the **Resolved** state. A successful payout or refund claim settles that position permanently.

## Displayed status and on-chain state

The interface calculates time-based statuses immediately from Solana cluster time. The stored on-chain state updates lazily when a resolution, claim, refund, exit, or settlement instruction evaluates the deadline.

This means the interface can display **Awaiting Resolution**, **Refunds Available**, or **Claim Period Expired** before a later transaction writes the corresponding state change on-chain.
