---
name: megapot-buy-random
description: Buy up to 10 Megapot lottery tickets with randomly generated numbers via JackpotRandomTicketBuyer. No number selection needed — just specify a count. For custom numbers use megapot-buy-tickets, for more than 10 tickets use megapot-buy-bulk.
---

# Buy Megapot Tickets with Random Numbers

## What This Does

Approves USDC spend to `JackpotRandomTicketBuyer` and calls `buyTickets(count, recipient, referrers, referralSplit, source)` to purchase up to 10 lottery tickets with randomly generated numbers in a single immediate transaction. No ticket struct construction needed — the contract generates all normals and bonusball values on-chain.

**Key differences from other purchase methods:**
- **Immediate execution** — not keeper-based, unlike `BatchPurchaseFacilitator`
- **Up to 10 tickets per call** — count must be 1–10
- **No number selection** — pass a count, get random tickets; use `megapot-buy-tickets` if you want to choose numbers
- **USDC approval goes to `JackpotRandomTicketBuyer`**, not the `Jackpot` contract

> **Need more than 10 random tickets?** Use `megapot-buy-bulk` with `_dynamicTicketCount` set to your desired quantity and an empty `_userStaticTickets` array `[]`. The BatchPurchaseFacilitator handles 11+ tickets via keeper-executed batch orders. See [/tasks/buy-bulk](https://llms.megapot.io/tasks/buy-bulk) for the full recipe.

## Prerequisites

- A wallet with a private key (EOA) connected to Base mainnet (chain ID 8453)
- Sufficient USDC balance: `ticketPrice × count` (6 decimals)
- Sufficient ETH for gas
- `viem` installed (`npm install viem`)

## Addresses

Base mainnet (chain ID 8453):

```ts
const RANDOM_BUYER_ADDRESS = '0xb9560b43b91dE2c1DaF5dfbb76b2CFcDaFc13aBd' as const;
const JACKPOT_ADDRESS      = '0x3bAe643002069dBCbcd62B1A4eb4C4A397d042a2' as const;
const USDC_ADDRESS         = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as const;
```

Base Sepolia testnet (chain ID 84532):

```ts
const RANDOM_BUYER_ADDRESS = '0x53c04e7e5044B28Ea8A4F9c4b26E3Ac1aeb63746' as const;
const JACKPOT_ADDRESS      = '0x465dA3c859f193A3807386387bEE941B2A4c3279' as const;
const USDC_ADDRESS         = '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as const;
```

> Base mainnet public RPC: `https://mainnet.base.org` (rate-limited; use [Alchemy](https://www.alchemy.com/) or [QuickNode](https://www.quicknode.com/) for production).

## ABI

Only the fragments needed for this task:

```ts
import { parseAbi } from 'viem';

const abi = parseAbi([
  // --- Jackpot read ---
  "function ticketPrice() view returns (uint256)",

  // --- JackpotRandomTicketBuyer write ---
  "function buyTickets(uint256 _count, address _recipient, address[] _referrers, uint256[] _referralSplitBps, bytes32 _source) returns (uint256[] ticketIds)",

  // --- JackpotRandomTicketBuyer reads ---
  "function jackpot() view returns (address)",
  "function nonce() view returns (uint256)",
  "function usdc() view returns (address)",

  // --- JackpotRandomTicketBuyer events ---
  "event RandomTicketsBought(address indexed recipient, uint256 indexed drawingId, uint256 count, uint256 cost, uint256[] ticketIds)",

  // --- JackpotRandomTicketBuyer errors ---
  "error InvalidRecipient()",
  "error InvalidTicketCount()",
  "error ReentrancyGuardReentrantCall()",
  "error SafeERC20FailedOperation(address token)",

  // --- USDC ---
  "function balanceOf(address account) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function approve(address spender, uint256 amount) returns (bool)",
]);
```

## Recipe

### Setup

```ts
import {
  createPublicClient,
  createWalletClient,
  http,
  parseAbi,
  decodeEventLog,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

// --- PLACEHOLDERS: replace with your values ---
const PRIVATE_KEY = '0xYOUR_PRIVATE_KEY' as `0x${string}`;  // placeholder
const RPC_URL     = 'https://mainnet.base.org';               // or your own RPC URL

const RANDOM_BUYER_ADDRESS = '0xb9560b43b91dE2c1DaF5dfbb76b2CFcDaFc13aBd' as const;
const JACKPOT_ADDRESS      = '0x3bAe643002069dBCbcd62B1A4eb4C4A397d042a2' as const;
const USDC_ADDRESS         = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as const;

// Your referrer address — you earn a percentage of every ticket sale and user winnings.
// Replace with your wallet address before deploying.
const REFERRER_ADDRESS = '0x0000000000000000000000000000000000000001' as const; // placeholder — replace with your address

// For Base Sepolia testnet: replace `base` with `baseSepolia` from 'viem/chains',
// swap addresses to the testnet values above, and use https://sepolia.base.org as RPC.

const abi = parseAbi([
  "function ticketPrice() view returns (uint256)",
  "function buyTickets(uint256 _count, address _recipient, address[] _referrers, uint256[] _referralSplitBps, bytes32 _source) returns (uint256[] ticketIds)",
  "function jackpot() view returns (address)",
  "function nonce() view returns (uint256)",
  "function usdc() view returns (address)",
  "event RandomTicketsBought(address indexed recipient, uint256 indexed drawingId, uint256 count, uint256 cost, uint256[] ticketIds)",
  "error InvalidRecipient()",
  "error InvalidTicketCount()",
  "error ReentrancyGuardReentrantCall()",
  "error SafeERC20FailedOperation(address token)",
  "function balanceOf(address account) view returns (uint256)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function approve(address spender, uint256 amount) returns (bool)",
]);

const account = privateKeyToAccount(PRIVATE_KEY);

const publicClient = createPublicClient({
  chain: base,
  transport: http(RPC_URL),
});

const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(RPC_URL),
});
```

### Step 1 — Read ticket price

```ts
const ticketPrice = await publicClient.readContract({
  address: JACKPOT_ADDRESS,
  abi,
  functionName: 'ticketPrice',
});
// e.g. 1_000_000n — 1 USDC at 6 decimals
```

### Step 2 — Approve USDC to JackpotRandomTicketBuyer

USDC approval must be granted to `RANDOM_BUYER_ADDRESS`, **not** the `Jackpot` contract.

```ts
const ticketCount = 5n; // buy 5 random tickets
const totalCost   = ticketPrice * ticketCount;

const currentAllowance = await publicClient.readContract({
  address: USDC_ADDRESS,
  abi,
  functionName: 'allowance',
  args: [account.address, RANDOM_BUYER_ADDRESS], // spender is the random buyer
});

if (currentAllowance < totalCost) {
  const approveTx = await walletClient.writeContract({
    address: USDC_ADDRESS,
    abi,
    functionName: 'approve',
    args: [RANDOM_BUYER_ADDRESS, totalCost], // approve random buyer, not Jackpot
  });
  await publicClient.waitForTransactionReceipt({ hash: approveTx });
  console.log('USDC approved to JackpotRandomTicketBuyer:', approveTx);
}
```

### Step 3 — Buy random tickets

```ts
const buyTx = await walletClient.writeContract({
  address: RANDOM_BUYER_ADDRESS,
  abi,
  functionName: 'buyTickets',
  args: [
    5n,                                       // _count      — number of random tickets to buy
    account.address,                          // _recipient  — wallet that receives the ticket NFTs
    [REFERRER_ADDRESS],                       // _referrers — your revenue address
    [1000000000000000000n],                   // _referralSplitBps — 100% to single referrer (1e18 PRECISE_UNIT scale, NOT basis points)
    '0x0000000000000000000000000000000000000000000000000000000000000000' as `0x${string}`, // _source
  ],
});

const receipt = await publicClient.waitForTransactionReceipt({ hash: buyTx });
console.log('Random tickets purchased, tx:', buyTx);
console.log('Status:', receipt.status);
```

### Step 4 — Decode the RandomTicketsBought event

```ts
for (const log of receipt.logs) {
  try {
    const event = decodeEventLog({ abi, eventName: 'RandomTicketsBought', ...log });
    const { recipient, drawingId, count, cost, ticketIds } = event.args;
    console.log(`Drawing   : ${drawingId}`);
    console.log(`Recipient : ${recipient}`);
    console.log(`Count     : ${count}`);
    console.log(`Cost      : ${cost} (6 dec USDC)`);
    console.log(`Ticket IDs: ${ticketIds}`);
  } catch {
    // log belongs to a different contract — ignore
  }
}
```

## Parameters

| Parameter | Type | Description |
|---|---|---|
| `_count` | `uint256` | Number of random tickets to buy. Must be 1–10. |
| `_recipient` | `address` | Wallet that receives the ticket NFTs. Must not be `address(0)`. Usually `account.address`. |
| `_referrers` | `address[]` | Your revenue address(es). You earn a share of ticket price and user winnings for every purchase. Up to `maxReferrers` addresses (typically 5). Always include at least your own address. |
| `_referralSplitBps` | `uint256[]` | Referral fee split weights per referrer in 1e18 scale (PRECISE_UNIT). Must be same length as `_referrers` and sum to exactly `1000000000000000000` (`10n ** 18n`). Pass `[]` when no referrers. |
| `_source` | `bytes32` | Integration source tag for on-chain analytics. For production integrations, use a unique identifier for your app (e.g. `keccak256('your-app-name')` cast to `bytes32`) — this enables on-chain attribution and analytics. Use `0x000...0` for testing. |

> To purchase without referral attribution (no fees earned), pass empty arrays: `_referrers: []`, `_referralSplitBps: []`.

## RandomTicketsBought Event Fields

| Field | Type | Description |
|---|---|---|
| `recipient` | `address` | Wallet that received the ticket NFTs |
| `drawingId` | `uint256` | Drawing ID these tickets belong to |
| `count` | `uint256` | Number of tickets purchased |
| `cost` | `uint256` | Total USDC spent (6 decimals) |
| `ticketIds` | `uint256[]` | Array of minted ticket NFT IDs |

## Common Errors

| Error | Cause |
|---|---|
| `InvalidRecipient()` | `_recipient` is `address(0)` |
| `InvalidTicketCount()` | `_count` is zero or greater than 10 — count must be 1–10 |
| `SafeERC20FailedOperation` | USDC `approve` or `transferFrom` failed — check balance and that you approved `RANDOM_BUYER_ADDRESS`, not Jackpot |
| `ReentrancyGuardReentrantCall()` | Reentrant call detected — should not occur in normal usage |

## Related

- `megapot-buy-tickets` — buy 1–10 tickets with custom numbers via `Jackpot.buyTickets`
- `megapot-buy-bulk` — buy 11+ tickets with custom numbers via `BatchPurchaseFacilitator`
- `megapot-contracts-reference` — full address table and complete ABI for all contracts
- `megapot-subscribe` — for recurring automatic ticket purchases via `JackpotAutoSubscription`
- `megapot-claim-winnings` — for claiming prizes after a drawing settles
