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

# Program

> Raffle program instructions and account structures

# Program

This page documents the Private Raffle program's instructions and account structures.

## Account Structures

### Lottery

The main raffle account:

```rust theme={null}
#[account]
pub struct Lottery {
    pub authority: Pubkey,           // Raffle creator
    pub lottery_id: u64,             // Unique identifier
    pub ticket_price: u64,           // Price in lamports
    pub participant_count: u32,      // Number of tickets sold
    pub is_open: bool,               // Can still buy tickets?
    pub winning_number_handle: u128, // Encrypted winning number
    pub bump: u8,
}
```

### Ticket

Each player's ticket:

```rust theme={null}
#[account]
pub struct Ticket {
    pub lottery: Pubkey,          // Associated raffle
    pub owner: Pubkey,            // Ticket owner
    pub guess_handle: u128,       // Encrypted guess (1-100)
    pub is_winner_handle: u128,   // Encrypted: guess == winning?
    pub prize_handle: u128,       // Encrypted prize amount
    pub claimed: bool,            // Has claimed?
    pub bump: u8,
}
```

***

## Instructions

### create\_lottery

Creates a new raffle.

```rust theme={null}
pub fn create_lottery(
    ctx: Context<CreateLottery>,
    lottery_id: u64,      // Unique raffle ID
    ticket_price: u64     // Price per ticket (lamports)
) -> Result<()>
```

**Accounts:**

```rust theme={null}
#[derive(Accounts)]
#[instruction(lottery_id: u64)]
pub struct CreateLottery<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,
    
    #[account(
        init, 
        payer = authority, 
        space = Lottery::SIZE,
        seeds = [b"lottery", lottery_id.to_le_bytes().as_ref()], 
        bump
    )]
    pub lottery: Account<'info, Lottery>,
    
    /// CHECK: vault PDA for holding prize pool
    #[account(mut, seeds = [b"vault", lottery.key().as_ref()], bump)]
    pub vault: AccountInfo<'info>,
    
    pub system_program: Program<'info, System>,
}
```

***

### buy\_ticket

Purchase a ticket with an encrypted guess.

```rust theme={null}
pub fn buy_ticket(
    ctx: Context<BuyTicket>,
    encrypted_guess: Vec<u8>  // Encrypted guess (1-100)
) -> Result<()>
```

**What it does:**

1. Transfers ticket price to vault
2. Creates encrypted handle from guess
3. Stores ticket with encrypted guess
4. Allows buyer to decrypt their own guess

**Accounts:**

```rust theme={null}
#[derive(Accounts)]
pub struct BuyTicket<'info> {
    #[account(mut)]
    pub buyer: Signer<'info>,
    
    #[account(mut)]
    pub lottery: Account<'info, Lottery>,
    
    #[account(
        init, 
        payer = buyer, 
        space = Ticket::SIZE,
        seeds = [b"ticket", lottery.key().as_ref(), buyer.key().as_ref()], 
        bump
    )]
    pub ticket: Account<'info, Ticket>,
    
    /// CHECK: vault PDA
    #[account(mut, seeds = [b"vault", lottery.key().as_ref()], bump)]
    pub vault: AccountInfo<'info>,
    
    pub system_program: Program<'info, System>,
    pub inco_lightning_program: Program<'info, IncoLightning>,
}
```

***

### draw\_winner

Authority sets the encrypted winning number and closes the raffle.

```rust theme={null}
pub fn draw_winner(
    ctx: Context<DrawWinner>,
    encrypted_winning_number: Vec<u8>  // Encrypted winning number
) -> Result<()>
```

**What it does:**

1. Verifies caller is authority
2. Closes the raffle (`is_open = false`)
3. Stores encrypted winning number

***

### check\_winner

Compares a ticket's guess against the winning number (encrypted comparison).

```rust theme={null}
pub fn check_winner(ctx: Context<CheckWinner>) -> Result<()>
```

**What it does:**

1. Uses `e_eq` to compare `guess_handle` with `winning_number_handle`
2. Stores encrypted boolean result in `is_winner_handle`
3. Allows ticket owner to decrypt the result

**Key encrypted operation:**

```rust theme={null}
// Encrypted comparison: guess == winning_number?
let is_winner: Ebool = cpi::e_eq(
    cpi_ctx,
    Euint128(ticket.guess_handle),
    Euint128(lottery.winning_number_handle),
    0,
)?;

ticket.is_winner_handle = is_winner.0;
```

***

### claim\_prize

Calculates the encrypted prize amount based on win/loss status.

```rust theme={null}
pub fn claim_prize(ctx: Context<ClaimPrize>) -> Result<()>
```

**What it does:**

1. Creates encrypted prize amount (vault balance)
2. Creates encrypted zero
3. Uses `e_select`: if winner, get prize; else get 0
4. Stores encrypted prize amount
5. Marks ticket as claimed

**Key encrypted operation:**

```rust theme={null}
// e_select: if winner, get prize; else get 0
let actual_prize: Euint128 = e_select(
    cpi_ctx,
    Ebool(ticket.is_winner_handle),  // condition
    encrypted_prize,                  // if true
    zero,                             // if false
    0,
)?;

ticket.prize_handle = actual_prize.0;
```

***

### withdraw\_prize

Winner withdraws their prize with on-chain signature verification.

```rust theme={null}
pub fn withdraw_prize(
    ctx: Context<WithdrawPrize>,
    handle: Vec<u8>,      // Prize handle as bytes
    plaintext: Vec<u8>    // Decrypted prize amount
) -> Result<()>
```

**What it does:**

1. Verifies ticket owner and claimed status
2. Verifies Ed25519 signature on-chain (proves decryption is valid)
3. Parses plaintext to get prize amount
4. Rejects if prize is 0 (not a winner)
5. Transfers SOL from vault to winner

**Key verification:**

```rust theme={null}
// Verify the decryption signature on-chain
cpi::is_validsignature(
    cpi_ctx,
    1,
    Some(vec![handle]),
    Some(vec![plaintext.clone()]),
)?;

// Parse verified plaintext
let prize_amount = parse_plaintext_to_u64(&plaintext)?;
require!(prize_amount > 0, LotteryError::NotWinner);
```

***

## Error Codes

```rust theme={null}
#[error_code]
pub enum LotteryError {
    #[msg("Lottery is closed")]
    LotteryClosed,
    #[msg("Lottery is still open")]
    LotteryStillOpen,
    #[msg("No winning number set")]
    NoWinningNumber,
    #[msg("No participants")]
    NoParticipants,
    #[msg("Not ticket owner")]
    NotOwner,
    #[msg("Already claimed")]
    AlreadyClaimed,
    #[msg("Ticket not checked yet")]
    NotChecked,
    #[msg("Not claimed yet")]
    NotClaimed,
    #[msg("Not the winner")]
    NotWinner,
    #[msg("Unauthorized")]
    Unauthorized,
}
```

***

## PDA Seeds

| Account | Seeds                                      |
| ------- | ------------------------------------------ |
| Lottery | `["lottery", lottery_id]`                  |
| Vault   | `["vault", lottery_pubkey]`                |
| Ticket  | `["ticket", lottery_pubkey, buyer_pubkey]` |

## Next Steps

See [Client Integration](/svm/tutorials/private-raffle/client) for TypeScript usage examples.
