# Add Megapot to Your Site

This guide walks you through integrating Megapot into your dApp. Follow these four steps to build a complete lottery experience:

1. [Display Prize Information](#1-display-prize-information) - Show users the current jackpot and prize tiers
2. [Buy Tickets](#2-buy-tickets) - Let users purchase tickets
3. [Display User Tickets](#3-display-user-tickets) - Show users their ticket holdings
4. [Claim Winnings](#4-claim-winnings) - Allow users to claim their prizes

For contract addresses and ABIs, see the [Contract Overview](https://docs.megapot.io/developers/contract-overview).

***

## 1. Display Prize Information

Show users the current jackpot and prize tier payouts.

**Contracts:**

* Jackpot: `0x3bAe643002069dBCbcd62B1A4eb4C4A397d042a2`
* PayoutCalculator: `0x97a22361b6208aC8cd9afaea09D20feC47046CBD`

### Get Current Drawing Info

```typescript
const drawingId = await jackpot.currentDrawingId();
const state = await jackpot.getDrawingState(drawingId);

const currentJackpot = Number(state.prizePool) / 1e6;  // USDC amount
const ticketPrice = Number(state.ticketPrice) / 1e6;   // USDC amount
const bonusballMax = Number(state.bonusballMax);
```

### Fetch All Prize Tier Payouts

```typescript
const payouts = await payoutCalculator.getExpectedDrawingTierPayouts(
    drawingId,
    state.prizePool,
    state.ballMax,
    state.bonusballMax
);

// Format for display (payouts are in USDC wei, 6 decimals)
const prizes = {
    jackpot: Number(payouts[11]) / 1e6,        // 5 matches + bonusball
    fiveMatch: Number(payouts[10]) / 1e6,      // 5 matches
    fourPlusBonus: Number(payouts[9]) / 1e6,   // 4 matches + bonusball
    fourMatch: Number(payouts[8]) / 1e6,       // 4 matches
    threePlusBonus: Number(payouts[7]) / 1e6,  // 3 matches + bonusball
    threeMatch: Number(payouts[6]) / 1e6,      // 3 matches
    twoPlusBonus: Number(payouts[5]) / 1e6,    // 2 matches + bonusball
    twoMatch: Number(payouts[4]) / 1e6,        // 2 matches
    onePlusBonus: Number(payouts[3]) / 1e6,    // 1 match + bonusball
    bonusOnly: Number(payouts[1]) / 1e6,       // bonusball only
};
```

### Prize Tier Mapping

The 12 tiers are calculated as `(normalMatches * 2) + bonusballMatch`:

| Tier | Matches | Bonusball | Description             |
| ---- | ------- | --------- | ----------------------- |
| 1    | 0       | Yes       | Bonusball only          |
| 3    | 1       | Yes       | 1 match + bonusball     |
| 4    | 2       | No        | 2 matches               |
| 5    | 2       | Yes       | 2 matches + bonusball   |
| 6    | 3       | No        | 3 matches               |
| 7    | 3       | Yes       | 3 matches + bonusball   |
| 8    | 4       | No        | 4 matches               |
| 9    | 4       | Yes       | 4 matches + bonusball   |
| 10   | 5       | No        | 5 matches               |
| 11   | 5       | Yes       | Jackpot (5 + bonusball) |

Tiers 0 and 2 (0 matches and 1 match without bonusball) have no payout.

For complete details on the payout calculation system, see [PayoutCalculator](https://docs.megapot.io/developers/contract-overview/payout-calculator).

***

## 2. Buy Tickets

Choose the right purchase method based on your use case.

### Quick Reference

| Scenario                     | Contract                                                                 | Execution       | Ticket Types     |
| ---------------------------- | ------------------------------------------------------------------------ | --------------- | ---------------- |
| <=10 tickets, single drawing | [`Jackpot`](#direct-purchase-jackpotbuytickets)                          | Immediate       | Static only      |
| <=10 tickets, random numbers | [`JackpotRandomTicketBuyer`](#random-tickets-jackpotrandomticketbuyer)   | Immediate       | Dynamic only     |
| >10 tickets, single drawing  | [`BatchPurchaseFacilitator`](#batch-purchase-batchpurchasefacilitator)   | Keeper-executed | Static + Dynamic |
| Multiple drawings            | [`JackpotAutoSubscription`](#recurring-purchase-jackpotautosubscription) | Keeper-executed | Static + Dynamic |

### Key Concepts

#### Static vs Dynamic Tickets

**Static tickets** are user-defined number combinations. Your dApp specifies exactly which 5 normal numbers and bonusball to play.

**Dynamic tickets** are randomly generated on-chain. The contract generates valid random numbers at execution time.

#### Ticket Structure

All methods use the same ticket format:

```typescript
interface Ticket {
    normals: number[];  // 5 unique numbers in [1, 30], sorted ascending
    bonusball: number;  // 1 number in [1, bonusballMax]
}
```

The `bonusballMax` varies by drawing - read it from `getDrawingState()`.

#### Recommended Limits

When using `BatchPurchaseFacilitator` or `JackpotAutoSubscription`:

* **Limit static tickets to 100 per order**
* If purchasing more than 100 tickets, make the rest dynamic

#### USDC Approval

Before purchasing, approve USDC spending on the correct contract:

```typescript
const ticketCount = 5;
const totalCost = ticketPrice * BigInt(ticketCount);

// Approve the contract that will receive the payment
await usdc.approve(contractAddress, totalCost);
```

| Method                                       | Approve USDC to          |
| -------------------------------------------- | ------------------------ |
| `Jackpot.buyTickets`                         | Jackpot                  |
| `JackpotRandomTicketBuyer.buyTickets`        | JackpotRandomTicketBuyer |
| `BatchPurchaseFacilitator.createBatchOrder`  | BatchPurchaseFacilitator |
| `JackpotAutoSubscription.createSubscription` | JackpotAutoSubscription  |

***

### Direct Purchase: `Jackpot.buyTickets`

**When to use:** 1-10 tickets where you want control over number selection.

**Contract:** `0x3bAe643002069dBCbcd62B1A4eb4C4A397d042a2`

```typescript
// 1. Get ticket price
const drawingId = await jackpot.currentDrawingId();
const state = await jackpot.getDrawingState(drawingId);
const ticketPrice = state.ticketPrice;

// 2. Define tickets
const tickets = [
    { normals: [7, 14, 21, 28, 30], bonusball: 12 },
    { normals: [3, 11, 19, 27, 29], bonusball: 8 }
];

// 3. Approve USDC
const totalCost = ticketPrice * BigInt(tickets.length);
await usdc.approve(jackpotAddress, totalCost);

// 4. Buy tickets
const tx = await jackpot.buyTickets(
    tickets,
    userAddress,      // recipient
    [],               // referrers (empty if none)
    [],               // referralSplit (empty if none)
    "0x0000000000000000000000000000000000000000000000000000000000000000"  // source
);

const receipt = await tx.wait();
// Tickets are minted immediately
```

#### Parameters

| Parameter        | Type        | Description                                                                                  |
| ---------------- | ----------- | -------------------------------------------------------------------------------------------- |
| `_tickets`       | `Ticket[]`  | Array of tickets (max 10). Each has `normals` (5 unique sorted numbers 1-30) and `bonusball` |
| `_recipient`     | `address`   | Address that will own the ticket NFTs                                                        |
| `_referrers`     | `address[]` | Referrer addresses for fee sharing. Pass `[]` if none                                        |
| `_referralSplit` | `uint256[]` | Weight for each referrer, scaled to 1e18. Pass `[]` if none                                  |
| `_source`        | `bytes32`   | Identifier for your application                                                              |

{% hint style="info" %}
To earn referrer fees, see [How to Earn by Referring](https://docs.megapot.io/developers/refer-to-earn) for details on the `_referrers` and `_referralSplit` parameters.
{% endhint %}

***

### Random Tickets: `JackpotRandomTicketBuyer`

**When to use:** Quick purchases where users don't care about specific numbers.

**Contract:** `0xb9560b43b91dE2c1DaF5dfbb76b2CFcDaFc13aBd`

```typescript
// 1. Get ticket price
const drawingId = await jackpot.currentDrawingId();
const state = await jackpot.getDrawingState(drawingId);
const ticketPrice = state.ticketPrice;

// 2. Approve USDC
const ticketCount = 5;
const totalCost = ticketPrice * BigInt(ticketCount);
await usdc.approve(randomTicketBuyerAddress, totalCost);

// 3. Buy random tickets
const tx = await randomTicketBuyer.buyTickets(
    ticketCount,
    userAddress,      // recipient
    [],               // referrers
    [],               // referralSplit
    "0x0000000000000000000000000000000000000000000000000000000000000000"  // source
);

const receipt = await tx.wait();
// Tickets with random numbers are minted immediately
```

***

### Batch Purchase: `BatchPurchaseFacilitator`

**When to use:** More than 10 tickets in a single drawing.

**Contract:** `0x01774B531591b286b9f02C6Bc02ab3fD9526Aa76`

Batch orders are prepaid and executed by protocol keepers. Supports a mix of static and dynamic tickets.

```typescript
// 1. Get ticket price
const drawingId = await jackpot.currentDrawingId();
const state = await jackpot.getDrawingState(drawingId);
const ticketPrice = state.ticketPrice;

// 2. Define order
const dynamicTicketCount = 40;  // Random tickets
const staticTickets = [
    { normals: [1, 2, 3, 4, 5], bonusball: 1 },
    { normals: [6, 7, 8, 9, 10], bonusball: 2 }
];

// 3. Approve USDC
const totalTickets = dynamicTicketCount + staticTickets.length;
const totalCost = ticketPrice * BigInt(totalTickets);
await usdc.approve(batchFacilitatorAddress, totalCost);

// 4. Create batch order
const tx = await batchFacilitator.createBatchOrder(
    userAddress,        // recipient
    dynamicTicketCount,
    staticTickets,
    [],                 // referrers
    []                  // referralSplit
);

await tx.wait();
// Order is queued - keepers will execute and mint tickets
```

#### Cancellation

```typescript
// Cancel and get refund for unexecuted tickets
await batchFacilitator.cancelBatchOrder();
```

Orders are also auto-cancelled if the drawing locks before execution completes.

***

### Recurring Purchase: `JackpotAutoSubscription`

**When to use:** Tickets across multiple drawings.

**Contract:** `0x02A58B725116BA687D9356Eafe0fA771d58a37ac`

```typescript
// 1. Get ticket price (locked for subscription duration)
const drawingId = await jackpot.currentDrawingId();
const state = await jackpot.getDrawingState(drawingId);
const ticketPrice = state.ticketPrice;

// 2. Define subscription
const totalDays = 30;
const dynamicTicketsPerDay = 5;
const staticTickets = [];  // Same numbers play every day

// 3. Approve USDC
const ticketsPerDay = dynamicTicketsPerDay + staticTickets.length;
const totalCost = ticketPrice * BigInt(totalDays) * BigInt(ticketsPerDay);
await usdc.approve(autoSubscriptionAddress, totalCost);

// 4. Create subscription
const tx = await autoSubscription.createSubscription(
    userAddress,           // recipient
    totalDays,
    dynamicTicketsPerDay,
    staticTickets,
    [],                    // referrers
    []                     // referralSplit
);

await tx.wait();
// Subscription active - tickets purchased each drawing
```

#### Cancellation

```typescript
// Cancel and get refund for remaining days
await autoSubscription.cancelSubscription();
```

***

## 3. Display User Tickets

Show users their ticket holdings.

**Contract:** JackpotTicketNFT (`0x48FfE35AbB9f4780a4f1775C2Ce1c46185b366e4`)

### Query Tickets for a Drawing

```typescript
const drawingId = await jackpot.currentDrawingId();
const tickets = await ticketNFT.getUserTickets(userAddress, drawingId);

const formattedTickets = tickets.map(t => ({
    id: t.ticketId.toString(),
    numbers: t.normals.map(n => Number(n)),
    bonusball: Number(t.bonusball),
    drawingId: Number(t.ticket.drawingId)
}));

console.log(formattedTickets);
// [{ id: "123", numbers: [7, 14, 21, 28, 30], bonusball: 12, drawingId: 42 }, ...]
```

### Query Tickets Across Multiple Drawings

```typescript
async function getAllUserTickets(userAddress: string, fromDrawingId: number, toDrawingId: number) {
    const allTickets = [];

    for (let drawingId = fromDrawingId; drawingId <= toDrawingId; drawingId++) {
        const tickets = await ticketNFT.getUserTickets(userAddress, drawingId);
        allTickets.push(...tickets.map(t => ({
            id: t.ticketId.toString(),
            numbers: t.normals.map(n => Number(n)),
            bonusball: Number(t.bonusball),
            drawingId
        })));
    }

    return allTickets;
}
```

### Get Single Ticket Details

```typescript
const ticket = await ticketNFT.getExtendedTicketInfo(ticketId);

console.log({
    id: ticket.ticketId.toString(),
    drawingId: Number(ticket.ticket.drawingId),
    numbers: ticket.normals.map(n => Number(n)),
    bonusball: Number(ticket.bonusball)
});
```

For complete ticket NFT documentation, see [JackpotTicketNFT](https://docs.megapot.io/developers/contract-overview/jackpot-ticket-nft).

***

## 4. Claim Winnings

Allow users to claim prizes from winning tickets.

**Contract:** Jackpot (`0x3bAe643002069dBCbcd62B1A4eb4C4A397d042a2`)

### Complete Claim Flow

```typescript
async function claimWinnings(userAddress: string, drawingId: number) {
    // 1. Check drawing is complete
    const state = await jackpot.getDrawingState(drawingId);
    if (state.phase !== 4) { // 4 = COMPLETE
        throw new Error('Drawing not yet complete');
    }

    // 2. Get user's tickets for this drawing
    const tickets = await ticketNFT.getUserTickets(userAddress, drawingId);
    if (tickets.length === 0) {
        return { message: 'No tickets for this drawing' };
    }

    const ticketIds = tickets.map(t => t.ticketId);

    // 3. Check which tickets won
    const tierIds = await jackpot.getTicketTierIds(ticketIds);
    const tierPayouts = await jackpot.getDrawingTierPayouts(drawingId);

    // 4. Filter to winning tickets and calculate payout
    const winningTickets = [];
    let totalPayout = 0n;

    for (let i = 0; i < ticketIds.length; i++) {
        const tierId = Number(tierIds[i]);
        if (tierId > 0) {
            winningTickets.push(ticketIds[i]);
            totalPayout += tierPayouts[tierId];
        }
    }

    if (winningTickets.length === 0) {
        return { message: 'No winning tickets' };
    }

    // 5. Claim winnings (tickets are burned, USDC transferred)
    const tx = await jackpot.claimWinnings(winningTickets);
    await tx.wait();

    return {
        ticketsClaimed: winningTickets.length,
        totalPayout: Number(totalPayout) / 1e6  // USDC amount
    };
}
```

### Check Win Status Without Claiming

```typescript
async function checkWinnings(userAddress: string, drawingId: number) {
    const tickets = await ticketNFT.getUserTickets(userAddress, drawingId);
    const ticketIds = tickets.map(t => t.ticketId);

    const tierIds = await jackpot.getTicketTierIds(ticketIds);
    const tierPayouts = await jackpot.getDrawingTierPayouts(drawingId);

    return tickets.map((ticket, i) => {
        const tierId = Number(tierIds[i]);
        return {
            ticketId: ticket.ticketId.toString(),
            numbers: ticket.normals.map(n => Number(n)),
            bonusball: Number(ticket.bonusball),
            won: tierId > 0,
            tier: tierId,
            payout: tierId > 0 ? Number(tierPayouts[tierId]) / 1e6 : 0
        };
    });
}
```

### Important Notes

* Tickets are burned when claimed - they cannot be claimed twice
* Only the ticket owner (or approved address) can claim
* For large numbers of tickets (>75), split claims across multiple transactions to avoid gas limits
* Winnings are paid in USDC to the address that calls `claimWinnings`

For complete Jackpot contract documentation, see [Jackpot](https://docs.megapot.io/developers/contract-overview/jackpot).
