1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use anchor_lang::prelude::*;

use crate::{constants::*, errors::AuctionHouseError, AuctionHouse, Auctioneer, AuthorityScope};

/// Accounts for the [`delegate_auctioneer` handler](auction_house/fn.delegate_auctioneer.html).
#[derive(Accounts)]
pub struct DelegateAuctioneer<'info> {
    // Auction House instance PDA account.
    #[account(
        mut,
        seeds = [
            PREFIX.as_bytes(),
            auction_house.creator.as_ref(),
            auction_house.treasury_mint.as_ref()
        ],
        bump=auction_house.bump,
        has_one=authority
    )]
    pub auction_house: Account<'info, AuctionHouse>,

    #[account(mut)]
    pub authority: Signer<'info>,

    /// CHECK: The auction house authority can set this to whatever external address they wish.
    /// The auctioneer authority - the program PDA running this auction.
    pub auctioneer_authority: UncheckedAccount<'info>,

    /// The auctioneer PDA owned by Auction House storing scopes.
    #[account(
        init,
        payer = authority,
        space = AUCTIONEER_SIZE,
        seeds = [
            AUCTIONEER.as_bytes(),
            auction_house.key().as_ref(),
            auctioneer_authority.key().as_ref()
        ],
        bump
    )]
    pub ah_auctioneer_pda: Account<'info, Auctioneer>,

    pub system_program: Program<'info, System>,
}

pub fn delegate_auctioneer<'info>(
    ctx: Context<'_, '_, '_, 'info, DelegateAuctioneer<'info>>,
    scopes: Vec<AuthorityScope>,
) -> Result<()> {
    if scopes.len() > MAX_NUM_SCOPES {
        return Err(AuctionHouseError::TooManyScopes.into());
    }

    let auction_house = &mut ctx.accounts.auction_house;

    if auction_house.has_auctioneer {
        return Err(AuctionHouseError::AuctionHouseAlreadyDelegated.into());
    }

    auction_house.has_auctioneer = true;
    auction_house.auctioneer_address = ctx.accounts.ah_auctioneer_pda.key();

    // Set all scopes false and then update as true the ones passed into the handler.
    auction_house.scopes = [false; MAX_NUM_SCOPES];
    for scope in scopes {
        auction_house.scopes[scope as usize] = true;
    }

    let auctioneer = &mut ctx.accounts.ah_auctioneer_pda;
    auctioneer.auctioneer_authority = ctx.accounts.auctioneer_authority.key();
    auctioneer.auction_house = ctx.accounts.auction_house.key();
    auctioneer.bump = *ctx
        .bumps
        .get("ah_auctioneer_pda")
        .ok_or(AuctionHouseError::BumpSeedNotInHashMap)?;

    Ok(())
}