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

# Displaying Jackpot

This example will guide you through displaying the jackpot's size, ticket price, odds of winning and a countdown to the next drawing along with a section for claiming winnings and the last jackpot results.

This references our Jackpot Demo Integration Github Repo.  You can find the code for the demo integration [here](https://github.com/coordinationlabs/megapot-standalone-demo) or view the live demo [here](https://megapot-standalone-demo.vercel.app/).

## Jackpot Page

This is the entry point for the jackpot page.

```tsx theme={null}
// /app/jackpot/page.tsx

import { JackpotComponent } from '@/components/jackpot-component';

export default function JackpotPage() {
    return <JackpotComponent />;
}
```

## Jackpot Component

* This component will display the jackpot's size, ticket price, odds of winning and a countdown to the next drawing.
* This component will also display a form to purchase tickets.

```tsx theme={null}
// /app/components/jackpot-component.tsx
'use client';

import { Card, CardContent } from '@/components/ui/card';
import { getUsersInfo } from '@/lib/contract';
import { useEffect, useState } from 'react';
import { useAccount } from 'wagmi';
import { BuyTickets } from './jackpot-components/buy-tickets';
import { Countdown } from './jackpot-components/countdown';
import { CurrentJackpot } from './jackpot-components/current-jackpot';
import { LastJackpot } from './jackpot-components/last-jackpot';
import { TicketPrice } from './jackpot-components/ticket-price';
import { WinningOdds } from './jackpot-components/winning-odds';
import { WithdrawWinnings } from './jackpot-components/withdraw-winnings';

export function JackpotComponent() {
    const { address, isConnected } = useAccount();

    const [winningsAvailable, setWinningsAvailable] = useState<number>(0);

    useEffect(() => {
        if (!address) return;
        const fetchWinningsAvailable = async () => {
            const usersInfo = await getUsersInfo(address);
            if (!usersInfo) return;
            const winningsAvailable = usersInfo.winningsClaimable;
            setWinningsAvailable(Number(winningsAvailable));
        };
        fetchWinningsAvailable();
    }, [address]);
    return (
        <div className="space-y-6">
            {winningsAvailable > 0 && (
                <WithdrawWinnings winningsAvailable={winningsAvailable} />
            )}

            <CurrentJackpot />

            <Countdown />

            <Card className="bg-white rounded-xl shadow-sm">
                <CardContent className="p-6">
                    <div className="text-center">
                        <TicketPrice />
                        <WinningOdds />
                        {isConnected && address && (
                            <BuyTickets walletAddress={address} />
                        )}
                    </div>
                </CardContent>
            </Card>

            <LastJackpot />
        </div>
    );
}
```

## Buy Tickets

This component will display the current jackpot's size.

```tsx theme={null}
// /app/components/jackpot-components/buy-tickets.tsx
import { BaseJackpotAbi } from '@/lib/abi';
import {
    CONTRACT_ADDRESS,
    ERC20_TOKEN_ADDRESS,
    REFERRER_ADDRESS,
} from '@/lib/constants';
import { getTokenAllowance, getTokenBalance } from '@/lib/contract';
import { useEffect, useState } from 'react';
import { parseAbi } from 'viem';
import { useAccount, useWriteContract } from 'wagmi';
import { ConnectButton } from '../connect-button';
import { Button } from '../ui/button';

export function BuyTickets({
    walletAddress,
}: {
    walletAddress: `0x${string}`;
}) {
    const { isConnected } = useAccount();

    const { data, error, isError, isPending, writeContract } =
        useWriteContract();
    const [ticketCount, setTicketCount] = useState<number>(1);
    const [walletFunded, setWalletFunded] = useState<boolean>(false);
    const [allowance, setAllowance] = useState<number>(0);

    const increment = () => setTicketCount((prev) => prev + 1);
    const decrement = () => setTicketCount((prev) => (prev > 1 ? prev - 1 : 1));

    useEffect(() => {
        // Get the balance of the wallet so we can check
        //  if it's funded
        const fetchWalletFunds = async () => {
            try {
                const balance = await getTokenBalance(walletAddress);
                if (balance) {
                    setWalletFunded(balance >= ticketCount * 10 ** 6);
                } else {
                    setWalletFunded(false);
                }
            } catch (error) {
                console.error('Error fetching wallet funded status:', error);
            }
        };

        // Fetch wallet funds every 5 seconds
        const intervalFunds = setInterval(fetchWalletFunds, 5000);
        fetchWalletFunds();

        // Get the allowance of the wallet so we can check
        //  if it's approved to buy tickets
        const fetchAllowance = async () => {
            try {
                const allowance = await getTokenAllowance(walletAddress);
                if (allowance) {
                    setAllowance(allowance);
                } else {
                    setAllowance(0);
                }
            } catch (error) {
                console.error('Error fetching allowance:', error);
            }
        };

        // Fetch allowance every 5 seconds
        const intervalAllowance = setInterval(fetchAllowance, 5000);
        fetchAllowance();

        return () => {
            clearInterval(intervalFunds);
            clearInterval(intervalAllowance);
        };
    }, [walletAddress]);

    const handleApproveToken = async () => {
        try {
            if (!walletAddress) {
                throw new Error('Wallet not connected');
            }

            const approveAbi = [
                'function approve(address spender, uint256 amount) returns (bool)',
            ];

            // Approve the token to be spent by the contract
            return writeContract?.({
                abi: parseAbi(approveAbi),
                address: ERC20_TOKEN_ADDRESS as `0x${string}`,
                functionName: 'approve',
                args: [CONTRACT_ADDRESS, walletAddress],
            });
        } catch (error) {
            console.error('Error approving token:', error);
        }
    };

    const handleBuyTicket = async () => {
        try {
            if (!walletAddress) {
                throw new Error('Wallet not connected');
            }

            const ticketCost = BigInt(1) * BigInt(10 ** 6);
            // This is YOUR wallet to collect referral fees
            const referrerAddress = REFERRER_ADDRESS;

            return writeContract?.({
                abi: BaseJackpotAbi,
                address: CONTRACT_ADDRESS as `0x${string}`,
                functionName: 'purchaseTickets',
                args: [referrerAddress, ticketCost, walletAddress],
            });
        } catch (error) {
            console.error('Error buying ticket:', error);
        }
    };

    return (
        <div className="flex flex-col items-center">
            <div className="flex items-center">
                <button
                    onClick={decrement}
                    className="bg-emerald-500 text-white px-2 hover:bg-emerald-600"
                >
                    -
                </button>
                <input
                    type="number"
                    value={ticketCount}
                    onChange={(e) =>
                        setTicketCount(Math.max(1, Number(e.target.value)))
                    }
                    className="mx-2 w-16 text-center border border-emerald-500 rounded"
                    min="1"
                    style={{ appearance: 'none', MozAppearance: 'textfield' }}
                />
                <button
                    onClick={increment}
                    className="bg-emerald-500 text-white px-2 hover:bg-emerald-600"
                >
                    +
                </button>
            </div>
            {isConnected &&
            walletFunded &&
            allowance >= ticketCount * 10 ** 6 ? (
                <Button
                    onClick={handleBuyTicket}
                    disabled={!isConnected || !walletFunded}
                    className="mt-2 w-full bg-emerald-500 hover:bg-emerald-600 text-white"
                >
                    Buy Ticket
                </Button>
            ) : isConnected &&
              walletFunded &&
              allowance < ticketCount * 10 ** 6 ? (
                <Button
                    onClick={handleApproveToken}
                    disabled={!isConnected}
                    className="mt-2 w-full bg-emerald-500 hover:bg-emerald-600 text-white"
                >
                    Approve USDC Token
                </Button>
            ) : isConnected && !walletFunded ? (
                <div className="mt-2 w-full bg-orange-500 hover:bg-orange-600 text-white">
                    Not enough USDC in wallet
                </div>
            ) : (
                <div className="mt-2 w-full bg-emerald-500 hover:bg-emerald-600 text-white">
                    <ConnectButton />
                </div>
            )}
        </div>
    );
}
```

## Countdown

This component will display a countdown to the next drawing.

```tsx theme={null}
// /app/components/jackpot-components/countdown.tsx
import { getTimeRemaining } from '@/lib/contract';
import { useEffect, useState } from 'react';
import { Card, CardContent } from '../ui/card';

export function Countdown() {
    const [timeRemaining, setTimeRemaining] = useState<string | null>(null);

    useEffect(() => {
        // Fetch time remaining
        const fetchTimeRemaining = async () => {
            const timeRemaining = await getTimeRemaining();
            if (timeRemaining) {
                setTimeRemaining(timeRemaining.toString());
            }
        };
        fetchTimeRemaining();

        // Update time remaining every second
        const timer = setInterval(() => {
            setTimeRemaining((prev) => {
                if (!prev) return null;

                const seconds = parseInt(prev, 10);
                if (seconds <= 0) return '0';

                return (seconds - 1).toString();
            });
        }, 1000);

        return () => clearInterval(timer);
    }, []);

    return (
        <Card className="bg-white rounded-xl shadow-sm">
            <CardContent className="p-6">
                <div className="text-center">
                    <h2 className="text-lg font-medium text-gray-500 mb-2">
                        Time Remaining
                    </h2>
                    <p className="text-3xl font-bold">
                        {timeRemaining
                            ? formatTime(parseInt(timeRemaining, 10))
                            : '--:--:--'}
                    </p>
                </div>
            </CardContent>
        </Card>
    );
}

const formatTime = (totalSeconds: number) => {
    if (totalSeconds <= 0) return '00:00:00';

    const hours = Math.floor(totalSeconds / 3600) % 24;
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = totalSeconds % 60;

    return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(
        2,
        '0'
    )}:${String(seconds).padStart(2, '0')}`;
};
```

## Current Jackpot

This component will display the current jackpot's size.

```tsx theme={null}
import { getJackpotAmount } from '@/lib/contract';
import { useEffect, useState } from 'react';
import { Card, CardContent } from '../ui/card';

export function CurrentJackpot() {
    const [jackpotAmount, setJackpotAmount] = useState<number | undefined>(
        undefined
    );

    useEffect(() => {
        const fetchJackpotAmount = async () => {
            const jackpotAmount = await getJackpotAmount();
            setJackpotAmount(jackpotAmount);
        };
        fetchJackpotAmount();
    }, []);

    return (
        <Card className="bg-white rounded-xl shadow-sm">
            <CardContent className="p-6">
                <div className="text-center">
                    <h2 className="text-lg font-medium text-gray-500 mb-2">
                        Current Jackpot
                    </h2>
                    <p className="text-4xl font-bold text-emerald-500">
                        {jackpotAmount
                            ? `$${jackpotAmount.toFixed(2)}`
                            : 'Loading...'}
                    </p>
                </div>
            </CardContent>
        </Card>
    );
}
```

## Last Jackpot

This component will display the last jackpot's results.

```tsx theme={null}
// /app/components/jackpot-components/last-jackpot.tsx

import { getLastJackpotResults } from '@/lib/contract';
import { useEffect, useState } from 'react';
import { zeroAddress } from 'viem';
import { Card, CardContent } from '../ui/card';

interface LastJackpotEvent {
    time: number;
    winner: string;
    winningTicket: number;
    winAmount: number;
    ticketsPurchasedTotalBps: number;
}
export function LastJackpot() {
    const [lastJackpot, setLastJackpot] = useState<
        LastJackpotEvent | undefined
    >(undefined);
    const [isLoading, setIsLoading] = useState(true);
    useEffect(() => {
        const fetchLastJackpot = async () => {
            const lastJackpot = await getLastJackpotResults();
            if (lastJackpot) {
                const lastJackpotEvent = {
                    time: lastJackpot.time,
                    winner: lastJackpot.winner,
                    winningTicket: lastJackpot.winningTicket / 7000, // Divide by 7000 to get the winning ticket number
                    winAmount: lastJackpot.winAmount,
                    ticketsPurchasedTotalBps:
                        lastJackpot.ticketsPurchasedTotalBps,
                };
                setLastJackpot(lastJackpotEvent);
                setIsLoading(false);
            }
        };
        fetchLastJackpot();
    }, []);
    return (
        <Card>
            <CardContent>
                <div className="flex flex-col items-center justify-center">
                    <h1 className="text-2xl font-bold">Last Jackpot</h1>
                    {lastJackpot && !isLoading ? (
                        <>
                            <div className="flex justify-between w-full">
                                <p className="text-lg text-emerald-500">
                                    Winner:
                                </p>
                                <p className="text-lg text-emerald-500">
                                    {lastJackpot.winner === zeroAddress
                                        ? 'LPs Won'
                                        : lastJackpot.winner}
                                </p>
                            </div>
                            <div className="flex justify-between w-full">
                                <p className="text-lg text-emerald-500">
                                    Win Amount:
                                </p>
                                <p className="text-lg text-emerald-500">
                                    {(lastJackpot.winAmount / 10 ** 6).toFixed(
                                        2
                                    )}{' '}
                                    USDC
                                </p>
                            </div>
                        </>
                    ) : (
                        <p className="text-lg">Loading...</p>
                    )}
                </div>
            </CardContent>
        </Card>
    );
}
```

## Ticket Price

This component will display the current ticket price.

```tsx theme={null}
// /app/components/jackpot-components/ticket-price.tsx

import { getTicketPrice } from '@/lib/contract';
import { useEffect, useState } from 'react';

export function TicketPrice() {
    const [ticketPrice, setTicketPrice] = useState<string | null>(null);

    useEffect(() => {
        const fetchTicketPrice = async () => {
            const price = await getTicketPrice();
            setTicketPrice(price?.toString() || null);
        };
        fetchTicketPrice();
    }, []);

    return (
        <div>
            <h2 className="text-lg font-medium text-gray-500 mb-2">
                Ticket Price
            </h2>
            <p className="text-2xl font-bold mb-4">{ticketPrice} USDC</p>
        </div>
    );
}
```

## Winning Odds

This component will display the odds of winning.

```tsx theme={null}
// /app/components/jackpot-components/winning-odds.tsx

import { getJackpotOdds } from '@/lib/contract';
import { useEffect, useState } from 'react';

export function WinningOdds() {
    const [jackpotOdds, setJackpotOdds] = useState<number | null>(null);

    useEffect(() => {
        const fetchJackpotOdds = async () => {
            const odds = await getJackpotOdds();
            setJackpotOdds(odds || null);
        };
        fetchJackpotOdds();
    }, []);

    return (
        <p className="text-sm text-gray-500 mb-4">
            Odds of winning: 1 in {Number(jackpotOdds).toFixed(2)}
        </p>
    );
}
```

## Withdraw Winnings

This component will display the form to withdraw winnings.

```tsx theme={null}

import { BaseJackpotAbi } from '@/lib/abi';
import { CONTRACT_ADDRESS } from '@/lib/constants';
import { useWriteContract } from 'wagmi';
import { Button } from '../ui/button';
import { Card, CardContent } from '../ui/card';

export function WithdrawWinnings({
    winningsAvailable,
}: {
    winningsAvailable: number;
}) {
    const { writeContract } = useWriteContract();
    const handleWithdraw = async () => {
        writeContract?.({
            address: CONTRACT_ADDRESS as `0x${string}`,
            abi: BaseJackpotAbi,
            functionName: 'withdrawWinnings',
            args: [],
        });
    };
    return (
        <Card className="bg-white rounded-xl shadow-sm">
            <CardContent className="p-6">
                <div className="flex flex-col items-center justify-center">
                    <h1 className="text-2xl font-bold">Withdraw Winnings</h1>
                    <p className="text-lg">
                        {(winningsAvailable / 10 ** 6).toFixed(2)} USDC
                    </p>
                    <Button
                        onClick={handleWithdraw}
                        className="mt-2 w-full bg-emerald-500 hover:bg-emerald-600 text-white"
                    >
                        Withdraw
                    </Button>
                </div>
            </CardContent>
        </Card>
    );
}
```

## API Route

This API route will fetch the past jackpot results from the contract using BaseScan's API.

```tsx theme={null}
// /app/api/past-jackpot.ts

import { CONTRACT_ADDRESS, CONTRACT_START_BLOCK, JACKPOT_RUN_TOPIC } from '@/lib/constants';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
    try {

        const urlParams = new URLSearchParams({
            module: 'logs',
            action: 'getLogs',
            address: CONTRACT_ADDRESS,
            topic0: JACKPOT_RUN_TOPIC,
            apikey: process.env.BASESCAN_API_KEY || '',
            fromBlock: CONTRACT_START_BLOCK.toString(),
        });

        const response = await fetch(
            `https://api.basescan.org/api?${urlParams.toString()}`,
            {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json',
                },
            }
        );

        const data = await response.json();
        // reverse the data
        const reversedData = data.result.reverse();

        return NextResponse.json(reversedData);
    } catch (error) {
        console.error('Error fetching from BaseScan:', error);
        return NextResponse.json(
            { message: 'Error fetching data' },
            { status: 500 }
        );
    }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.