---
# System prepended metadata

title: Burnt summary

---

# Burnt summary
## Metaplex



- How it work(High-level)
- Any importanat structure
- How many instructions here?
- How each instruction work? Does any check miss? 

## Auction

In big picture, this contract can create auction(auction, auction-extended) change authority of auction, then start auction, also end auction eariler. User can place bid(pot, pot-token, metadata), winner can claim bid, rest of users can cancel bid to get refund


### Programming Layout
The instructions are inside `/processor`
For each instruction, `parse_accounts` will do part of the privilege check, for example `owner`, `signer`


### Structure
- auction 
- auction extended data
- pot


### Instruction
#### 1. `CreateAuction(CreateAuctionArgs)` Create a new auction account bound to a resource, initially in a pending state
**Account Info:**

0. `[signer]` The account creating the auction, which is authorised to make changes.
1. `[writable]` Uninitialized auction account.
2. `[]` Rent sysvar
3. `[]` System account

[Question]:

/rust/auction/program/src/instruction.rs
```rust=
/// Create a new auction account bound to a resource, initially in a pending state.
///   0. `[signer]` The account creating the auction, which is authorised to make changes.
///   1. `[writable]` Uninitialized auction account.
///   2. `[]` Rent sysvar
///   3. `[]` System account
```
Should be 5 accounts, missing `auction_extended`

---
**Create Instruction(test purpose):**

<details>
	
```rust=
pub fn create_auction_instruction(
    program_id: Pubkey,
    creator_pubkey: Pubkey,
    args: CreateAuctionArgs,
) -> Instruction {
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        args.resource.as_ref(),
    ];
    let (auction_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    let seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        args.resource.as_ref(),
        EXTENDED.as_bytes(),
    ];
    let (auction_extended_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(creator_pubkey, true),
            AccountMeta::new(auction_pubkey, false),
            AccountMeta::new(auction_extended_pubkey, false),
            AccountMeta::new_readonly(sysvar::rent::id(), false),
            AccountMeta::new_readonly(solana_program::system_program::id(), false),
        ],
        data: AuctionInstruction::CreateAuction(args)
            .try_to_vec()
            .unwrap(),
    }
}
```
</details>

---

**Process:**

<details>

```rust=
pub fn create_auction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    args: CreateAuctionArgs,
) -> ProgramResult {
    msg!("+ Processing CreateAuction");
    let accounts = parse_accounts(program_id, accounts)?;

    let auction_path = [
        PREFIX.as_bytes(),
        program_id.as_ref(),
        &args.resource.to_bytes(),
    ];

    // Derive the address we'll store the auction in, and confirm it matches what we expected the
    // user to provide.
    let (auction_key, bump) = Pubkey::find_program_address(&auction_path, program_id);  // seeds, program_id
    if auction_key != *accounts.auction.key {
        return Err(AuctionError::InvalidAuctionAccount.into());
    }
    // The data must be large enough to hold at least the number of winners.
    let auction_size = match args.winners {
        WinnerLimit::Capped(n) => {
            mem::size_of::<Bid>() * BidState::max_array_size_for(n) + BASE_AUCTION_DATA_SIZE
        }
        WinnerLimit::Unlimited(_) => BASE_AUCTION_DATA_SIZE,
    };

    let bid_state = match args.winners {
        WinnerLimit::Capped(n) => BidState::new_english(n),
        WinnerLimit::Unlimited(_) => BidState::new_open_edition(),
        WinnerLimit::Capped(n) => BidState::new_dutch(n), // [Questuion] will never triggered?
    };

    if let Some(gap_tick) = args.gap_tick_size_percentage {
        if gap_tick > 100 {
            return Err(AuctionError::InvalidGapTickSizePercentage.into());
        }
    }

    // Create auction account with enough space for a winner tracking.
    create_or_allocate_account_raw(
        *program_id,
        accounts.auction,
        accounts.rent,
        accounts.system,
        accounts.payer,
        auction_size,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            &args.resource.to_bytes(),
            &[bump],
        ],
    )?;

    let auction_ext_bump = assert_derivation(
        program_id,
        accounts.auction_extended,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            &args.resource.to_bytes(),
            EXTENDED.as_bytes(),
        ],
    )?;

    create_or_allocate_account_raw(
        *program_id,
        accounts.auction_extended,
        accounts.rent,
        accounts.system,
        accounts.payer,
        MAX_AUCTION_DATA_EXTENDED_SIZE,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            &args.resource.to_bytes(),
            EXTENDED.as_bytes(),
            &[auction_ext_bump],
        ],
    )?;

    // Configure extended
    AuctionDataExtended {
        total_uncancelled_bids: 0,
        tick_size: args.tick_size,
        gap_tick_size_percentage: args.gap_tick_size_percentage,
        price_ceiling : args.price_ceiling,
        decrease_rate : args.decrease_rate,
        decrease_interval : args.decrease_interval
    }
    .serialize(&mut *accounts.auction_extended.data.borrow_mut())?;

    // Configure Auction.
    AuctionData {
        authority: args.authority,
        bid_state: bid_state,
        end_auction_at: args.end_auction_at,
        end_auction_gap: args.end_auction_gap,
        ended_at: None,
        last_bid: None,
        price_floor: args.price_floor,
        state: AuctionState::create(),
        token_mint: args.token_mint,
    }
    .serialize(&mut *accounts.auction.data.borrow_mut())?;

    Ok(())
}
```
	
</details>


[Question]:

/rust/auction/program/src/processor/create_auction.rs
```rust=107
    let bid_state = match args.winners {
        WinnerLimit::Capped(n) => BidState::new_english(n),
        WinnerLimit::Unlimited(_) => BidState::new_open_edition(),
        WinnerLimit::Capped(n) => BidState::new_dutch(n), // [Questuion] will never triggered?
    };
```
`new_dutch` will never be called?

---

#### 2. `SetAuthority` Update the authority for an auction account
	
	
**Account Info:**
1. auction account
2. authority
3. new authority

[Question] 
	
No Comment about account in this part.
	
**Create Instruction(test purpose):**

<details>

```rust=
/// Creates an SetAuthority instruction.
pub fn set_authority_instruction(
    program_id: Pubkey,
    resource: Pubkey,
    authority: Pubkey,
    new_authority: Pubkey,
) -> Instruction {
    let seeds = &[PREFIX.as_bytes(), &program_id.as_ref(), resource.as_ref()];
    let (auction_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);
    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(auction_pubkey, false),
            AccountMeta::new_readonly(authority, true),
            AccountMeta::new_readonly(new_authority, false),
        ],
        data: AuctionInstruction::SetAuthority.try_to_vec().unwrap(),
    }
}
```
</details>
	
**Process:**
	
```rust=
pub fn set_authority(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
    msg!("+ Processing SetAuthority");
    let account_iter = &mut accounts.iter();
    let auction_act = next_account_info(account_iter)?;
    let current_authority = next_account_info(account_iter)?;
    let new_authority = next_account_info(account_iter)?;

    let mut auction = AuctionData::from_account_info(auction_act)?;
    assert_owned_by(auction_act, program_id)?;

    if auction.authority != *current_authority.key {
        return Err(AuctionError::InvalidAuthority.into());
    }

    if !current_authority.is_signer {
        return Err(AuctionError::InvalidAuthority.into());
    }

    // Make sure new authority actually exists in some form.
    if new_authority.data_is_empty() || new_authority.lamports() == 0 {
        msg!("Disallowing new authority because it does not exist.");
        return Err(AuctionError::InvalidAuthority.into());
    }

    auction.authority = *new_authority.key;
    auction.serialize(&mut *auction_act.data.borrow_mut())?;
    Ok(())
}
```

[Question]

Should new authority also sign?

#### 3.`StartAuction(StartAuctionArgs)` Start an inactive auction
	
**Account Info:**
	
0. `[signer]` The creator/authorised account.
1. `[writable]` Initialized auction account.
2. `[]` Clock sysvar
	
**Create Instruction(test purpose):**

<details>
	
```rust=
/// Creates an StartAuction instruction.
pub fn start_auction_instruction(
    program_id: Pubkey,
    authority_pubkey: Pubkey,
    args: StartAuctionArgs,
) -> Instruction {
    // Derive Auction Key
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        args.resource.as_ref(),
    ];
    let (auction_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(authority_pubkey, true),
            AccountMeta::new(auction_pubkey, false),
            AccountMeta::new_readonly(sysvar::clock::id(), false),
        ],
        data: AuctionInstruction::StartAuction(args).try_to_vec().unwrap(),
    }
}
```
	
</details>
	
**Process:**

<details>

```rust=
pub fn start_auction<'a, 'b: 'a>(
    program_id: &Pubkey,
    accounts: &'a [AccountInfo<'b>],
    args: StartAuctionArgs,
) -> ProgramResult {
    msg!("+ Processing StartAuction");
    let accounts = parse_accounts(program_id, accounts)?;
    let clock = Clock::from_account_info(accounts.clock_sysvar)?;

    // Derive auction address so we can make the modifications necessary to start it.
    assert_derivation(
        program_id,
        accounts.auction,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            &args.resource.as_ref(),
        ],
    )?;

    // Initialise a new auction. The end time is calculated relative to now.
    let mut auction = AuctionData::from_account_info(accounts.auction)?;

    // Check authority is correct.
    if auction.authority != *accounts.authority.key {
        return Err(AuctionError::InvalidAuthority.into());
    }

    // Calculate the relative end time.
    let ended_at = if let Some(end_auction_at) = auction.end_auction_at {
        match clock.unix_timestamp.checked_add(end_auction_at) {
            Some(val) => Some(val),
            None => return Err(AuctionError::NumericalOverflowError.into()),
        }
    } else {
        None
    };

    AuctionData {
        ended_at,
        state: auction.state.start()?,
        ..auction
    }
    .serialize(&mut *accounts.auction.data.borrow_mut())?;

    Ok(())
}

```
	
</details>	
	
[Question]

~~rust/auction/program/src/processor/start_auction.rs~~
~~No signer check for authority?~~
	

#### 4.`PlaceBid(PlaceBidArgs)` Place a bid on a running auction
	
	
**Account Info:**
	
0. `[signer]` The bidders primary account, for PDA calculation/transit auth.
1. `[writable]` The bidders token account they'll pay with
2. `[writable]` The pot, containing a reference to the stored SPL token account.
3. `[writable]` The pot SPL account, where the tokens will be deposited.
4. `[writable]` The metadata account, storing information about the bidders actions.
5. `[writable]` Auction account, containing data about the auction and item being bid on.
6. `[writable]` Token mint, for transfer instructions and verification.
7. `[signer]` Transfer authority, for moving tokens into the bid pot.
8. `[signer]` Payer
9. `[]` Clock sysvar
10. `[]` Rent sysvar
11. `[]` System program
12. `[]` SPL Token Program

**Create Instruction(test purpose):**

<details>

```rust=
pub fn place_bid_instruction(
    program_id: Pubkey,
    bidder_pubkey: Pubkey,
    bidder_token_pubkey: Pubkey,
    bidder_pot_token_pubkey: Pubkey,
    token_mint_pubkey: Pubkey,
    transfer_authority: Pubkey,
    payer: Pubkey,
    args: PlaceBidArgs,
) -> Instruction {
    // Derive Auction Key
    let seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        args.resource.as_ref(),
    ];
    let (auction_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    let seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        args.resource.as_ref(),
        EXTENDED.as_bytes(),
    ];
    let (auction_extended_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    // Derive Bidder Pot
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        auction_pubkey.as_ref(),
        bidder_pubkey.as_ref(),
    ];
    let (bidder_pot_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    // Derive Bidder Meta
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        auction_pubkey.as_ref(),
        bidder_pubkey.as_ref(),
        "metadata".as_bytes(),
    ];
    let (bidder_meta_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(bidder_pubkey, true),
            AccountMeta::new(bidder_token_pubkey, false),
            AccountMeta::new(bidder_pot_pubkey, false),
            AccountMeta::new(bidder_pot_token_pubkey, false),
            AccountMeta::new(bidder_meta_pubkey, false),
            AccountMeta::new(auction_pubkey, false),
            AccountMeta::new(auction_extended_pubkey, false),
            AccountMeta::new(token_mint_pubkey, false),
            AccountMeta::new_readonly(transfer_authority, true),
            AccountMeta::new_readonly(payer, true),
            AccountMeta::new_readonly(sysvar::clock::id(), false),
            AccountMeta::new_readonly(sysvar::rent::id(), false),
            AccountMeta::new_readonly(solana_program::system_program::id(), false),
            AccountMeta::new_readonly(spl_token::id(), false),
        ],
        data: AuctionInstruction::PlaceBid(args).try_to_vec().unwrap(),
    }
}
```
	
</details>	
	
**Process:**

<details>

```rust=
#[allow(clippy::absurd_extreme_comparisons)]
pub fn place_bid<'r, 'b: 'r>(
    program_id: &Pubkey,
    accounts: &'r [AccountInfo<'b>],
    args: PlaceBidArgs,
) -> ProgramResult {
    msg!("+ Processing PlaceBid");
    let accounts = parse_accounts(program_id, accounts)?;

    // Load the auction and verify this bid is valid.
    let mut auction = AuctionData::from_account_info(accounts.auction)?;

    // Load the clock, used for various auction timing.
    let clock = Clock::from_account_info(accounts.clock_sysvar)?;

    // Verify auction has not ended.
    if auction.ended(clock.unix_timestamp)? {
        auction.state = auction.state.end()?;
        auction.serialize(&mut *accounts.auction.data.borrow_mut())?;
        msg!("Auction ended!");
        return Ok(());
    }
    // Derive Metadata key and load it.
    let metadata_bump = assert_derivation(
        program_id,
        accounts.bidder_meta,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            accounts.auction.key.as_ref(),
            accounts.bidder.key.as_ref(),
            "metadata".as_bytes(),
        ],
    )?;

    // If metadata doesn't exist, create it.
    if accounts.bidder_meta.owner != program_id {
        create_or_allocate_account_raw(
            *program_id,
            accounts.bidder_meta,
            accounts.rent,
            accounts.system,
            accounts.payer,
            // For whatever reason, using Mem function here returns 7, which is wholly wrong for this struct
            // seems to be issues with UnixTimestamp
            BIDDER_METADATA_LEN,
            &[
                PREFIX.as_bytes(),
                program_id.as_ref(),
                accounts.auction.key.as_ref(),
                accounts.bidder.key.as_ref(),
                "metadata".as_bytes(),
                &[metadata_bump],
            ],
        )?;
    } else {
        // Verify the last bid was cancelled before continuing.
        let bidder_metadata: BidderMetadata =
            BidderMetadata::from_account_info(accounts.bidder_meta)?;
        if bidder_metadata.cancelled == false {
            return Err(AuctionError::BidAlreadyActive.into());
        }
    };

    // Derive Pot address, this account wraps/holds an SPL account to transfer tokens into and is
    // also used as the authoriser of the SPL pot.
    let pot_bump = assert_derivation(
        program_id,
        accounts.bidder_pot,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            accounts.auction.key.as_ref(),
            accounts.bidder.key.as_ref(),
        ],
    )?;

    // The account within the pot must be owned by us.
    let actual_account: Account = assert_initialized(accounts.bidder_pot_token)?;
    if actual_account.owner != *accounts.auction.key {
        return Err(AuctionError::BidderPotTokenAccountOwnerMismatch.into());
    }

    if actual_account.delegate != COption::None {
        return Err(AuctionError::DelegateShouldBeNone.into());
    }

    if actual_account.close_authority != COption::None {
        return Err(AuctionError::CloseAuthorityShouldBeNone.into());
    }

    // Derive and load Auction.
    let auction_bump = assert_derivation(
        program_id,
        accounts.auction,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            args.resource.as_ref(),
        ],
    )?;

    // Can't bid on an auction that isn't running.
    if auction.state != AuctionState::Started {
        return Err(AuctionError::InvalidState.into());
    }

    let bump_authority_seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        accounts.auction.key.as_ref(),
        accounts.bidder.key.as_ref(),
        &[pot_bump],
    ];

    // If the bidder pot account is empty, we need to generate one.
    if accounts.bidder_pot.data_is_empty() {
        create_or_allocate_account_raw(
            *program_id,
            accounts.bidder_pot,
            accounts.rent,
            accounts.system,
            accounts.payer,
            mem::size_of::<BidderPot>(),
            bump_authority_seeds,
        )?;

        // Attach SPL token address to pot account.
        let mut pot = BidderPot::from_account_info(accounts.bidder_pot)?;
        pot.bidder_pot = *accounts.bidder_pot_token.key;
        pot.bidder_act = *accounts.bidder.key;
        pot.auction_act = *accounts.auction.key;
        pot.serialize(&mut *accounts.bidder_pot.data.borrow_mut())?;
    } else {
        // Already exists, verify that the pot contains the specified SPL address.
        let bidder_pot = BidderPot::from_account_info(accounts.bidder_pot)?;
        if bidder_pot.bidder_pot != *accounts.bidder_pot_token.key {
            return Err(AuctionError::BidderPotTokenAccountOwnerMismatch.into());
        }
    }

    // Update now we have new bid.
    assert_derivation(
        program_id,
        accounts.auction_extended,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            args.resource.as_ref(),
            EXTENDED.as_bytes(),
        ],
    )?;
    let mut auction_extended: AuctionDataExtended =
        AuctionDataExtended::from_account_info(accounts.auction_extended)?;
    auction_extended.total_uncancelled_bids = auction_extended
        .total_uncancelled_bids
        .checked_add(1)
        .ok_or(AuctionError::NumericalOverflowError)?;
    auction_extended.serialize(&mut *accounts.auction_extended.data.borrow_mut())?;

    // Confirm payers SPL token balance is enough to pay the bid.
    let account: Account = Account::unpack_from_slice(&accounts.bidder_token.data.borrow())?;
    if account.amount.saturating_sub(args.amount) < 0 {
        msg!(
            "Amount is too small: {:?}, compared to account amount of {:?}",
            args.amount,
            account.amount
        );
        return Err(AuctionError::BalanceTooLow.into());
    }

    // Transfer amount of SPL token to bid account.
    spl_token_transfer(TokenTransferParams {
        source: accounts.bidder_token.clone(),
        destination: accounts.bidder_pot_token.clone(),
        authority: accounts.transfer_authority.clone(),
        authority_signer_seeds: bump_authority_seeds,
        token_program: accounts.token_program.clone(),
        amount: args.amount,
    })?;

    // Serialize new Auction State
    auction.last_bid = Some(clock.unix_timestamp);
    auction.place_bid(
        Bid(*accounts.bidder.key, args.amount),
        auction_extended.tick_size,
        auction_extended.gap_tick_size_percentage,
        clock.unix_timestamp,
        auction_extended.price_ceiling,
        auction_extended.decrease_rate,
        auction_extended.decrease_interval
    )?;
    auction.serialize(&mut *accounts.auction.data.borrow_mut())?;

    // Update latest metadata with results from the bid.
    BidderMetadata {
        bidder_pubkey: *accounts.bidder.key,
        auction_pubkey: *accounts.auction.key,
        last_bid: args.amount,
        last_bid_timestamp: clock.unix_timestamp,
        cancelled: false,
    }
    .serialize(&mut *accounts.bidder_meta.data.borrow_mut())?;

    Ok(())
}

```
	
</details>

[Question]
	
1. Account: `metadata`, check for non-exist account, can only check owner?
```rust=
    // If metadata doesn't exist, create it.
    if accounts.bidder_meta.owner != program_id {
```
	
2. bid logic, need cancel bid first, then place a new bid

```rust=179
    } else {
        // Verify the last bid was cancelled before continuing.
        let bidder_metadata: BidderMetadata =
            BidderMetadata::from_account_info(accounts.bidder_meta)?;
        if bidder_metadata.cancelled == false {
            return Err(AuctionError::BidAlreadyActive.into());
        }
    };
```

3. How pot work, if `bidder_pot_token`'s owner is auction, how to get money back?
```rust=201
	// The account within the pot must be owned by us.
    let actual_account: Account = assert_initialized(accounts.bidder_pot_token)?;
    if actual_account.owner != *accounts.auction.key {
        return Err(AuctionError::BidderPotTokenAccountOwnerMismatch.into());
    }
```
	
`bidder_pot` to record the info(record), `bidder_pot_token` to hold token?	

metadata account:
```rust=
pub struct BidderMetadata {
    // Relationship with the bidder who's metadata this covers.
    pub bidder_pubkey: Pubkey,
    // Relationship with the auction this bid was placed on.
    pub auction_pubkey: Pubkey,
    // Amount that the user bid.
    pub last_bid: u64,
    // Tracks the last time this user bid.
    pub last_bid_timestamp: UnixTimestamp,
    // Whether the last bid the user made was cancelled. This should also be enough to know if the
    // user is a winner, as if cancelled it implies previous bids were also cancelled.
    pub cancelled: bool,
}
```

Bidder Pot
```rust=
pub struct BidderPot {
    /// Points at actual pot that is a token account
    pub bidder_pot: Pubkey,
    /// Originating bidder account
    pub bidder_act: Pubkey,
    /// Auction account
    pub auction_act: Pubkey,
    /// emptied or not
    pub emptied: bool,
}
```

- [ ] 4. not really the dutch auction?


	
rust/auction/program/src/processor.rs
```rust=
//Bid should be greater than the current ceiling price
if Some(bid.1) > maximum {
	BidState::assert_dutch_parameters(maximum, decrease_rate, decrease_interval, minimum)?
} 
```
	
	

	

#### 5. `CancelBid(CancelBidArgs)` Cancel a bid on a running auction
**Account Info:**

0. `[signer]` The bidders primary account, for PDA calculation/transit auth.
1. `[writable]` The bidders token account they'll receive refund with
2. `[writable]` The pot, containing a reference to the stored SPL token account.
3. `[writable]` The pot SPL account, where the tokens will be deposited.
4. `[writable]` The metadata account, storing information about the bidders actions.
5. `[writable]` Auction account, containing data about the auction and item being bid on.
6. `[writable]` Token mint, for transfer instructions and verification.
7. `[]` Clock sysvar
8. `[]` Rent sysvar
9. `[]` System program
10. `[]` SPL Token Program


**Create Instruction(test purpose):**

<details>

```rust=
/// Creates an CancelBidinstruction.
pub fn cancel_bid_instruction(
    program_id: Pubkey,
    bidder_pubkey: Pubkey,
    bidder_token_pubkey: Pubkey,
    bidder_pot_token_pubkey: Pubkey,
    token_mint_pubkey: Pubkey,
    args: CancelBidArgs,
) -> Instruction {
    // Derive Auction Key
    let seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        args.resource.as_ref(),
    ];
    let (auction_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    let seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        args.resource.as_ref(),
        EXTENDED.as_bytes(),
    ];
    let (auction_extended_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    // Derive Bidder Pot
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        auction_pubkey.as_ref(),
        bidder_pubkey.as_ref(),
    ];
    let (bidder_pot_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    // Derive Bidder Meta
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        auction_pubkey.as_ref(),
        bidder_pubkey.as_ref(),
        "metadata".as_bytes(),
    ];
    let (bidder_meta_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(bidder_pubkey, true),
            AccountMeta::new(bidder_token_pubkey, false),
            AccountMeta::new(bidder_pot_pubkey, false),
            AccountMeta::new(bidder_pot_token_pubkey, false),
            AccountMeta::new(bidder_meta_pubkey, false),
            AccountMeta::new(auction_pubkey, false),
            AccountMeta::new(auction_extended_pubkey, false),
            AccountMeta::new(token_mint_pubkey, false),
            AccountMeta::new_readonly(sysvar::clock::id(), false),
            AccountMeta::new_readonly(sysvar::rent::id(), false),
            AccountMeta::new_readonly(solana_program::system_program::id(), false),
            AccountMeta::new_readonly(spl_token::id(), false),
        ],
        data: AuctionInstruction::CancelBid(args).try_to_vec().unwrap(),
    }
}
```
	
	
</details>
	
**Process:**
	
<details>
	
```rust=
pub fn cancel_bid(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    args: CancelBidArgs,
) -> ProgramResult {
    msg!("+ Processing Cancelbid");
    let accounts = parse_accounts(program_id, accounts)?;

    // The account within the pot must be owned by us.
    let actual_account: Account = assert_initialized(accounts.bidder_pot_token)?;
    if actual_account.owner != *accounts.auction.key {
        return Err(AuctionError::BidderPotTokenAccountOwnerMismatch.into());
    }

    // Derive and load Auction.
    let auction_bump = assert_derivation(
        program_id,
        accounts.auction,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            args.resource.as_ref(),
        ],
    )?;

    let auction_seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        args.resource.as_ref(),
        &[auction_bump],
    ];

    // Load the auction and verify this bid is valid.
    let mut auction = AuctionData::from_account_info(accounts.auction)?;
    // The mint provided in this bid must match the one the auction was initialized with.
    if auction.token_mint != *accounts.mint.key {
        return Err(AuctionError::IncorrectMint.into());
    }

    // Load the clock, used for various auction timing.
    let clock = Clock::from_account_info(accounts.clock_sysvar)?;

    // Derive Metadata key and load it.
    let metadata_bump = assert_derivation(
        program_id,
        accounts.bidder_meta,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            accounts.auction.key.as_ref(),
            accounts.bidder.key.as_ref(),
            "metadata".as_bytes(),
        ],
    )?;

    // If metadata doesn't exist, error, can't cancel a bid that doesn't exist and metadata must
    // exist if a bid was placed.
    if accounts.bidder_meta.owner != program_id {
        return Err(AuctionError::MetadataInvalid.into());
    }

    // Derive Pot address, this account wraps/holds an SPL account to transfer tokens out of.
    let pot_seeds = [
        PREFIX.as_bytes(),
        program_id.as_ref(),
        accounts.auction.key.as_ref(),
        accounts.bidder.key.as_ref(),
    ];

    let pot_bump = assert_derivation(program_id, accounts.bidder_pot, &pot_seeds)?;

    let bump_authority_seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        accounts.auction.key.as_ref(),
        accounts.bidder.key.as_ref(),
        &[pot_bump],
    ];

    // If the bidder pot account is empty, this bid is invalid.
    if accounts.bidder_pot.data_is_empty() {
        return Err(AuctionError::BidderPotDoesNotExist.into());
    }

    // Refuse to cancel if the auction ended and this person is a winning account.
    if auction.ended(clock.unix_timestamp)? && auction.is_winner(accounts.bidder.key).is_some() {
        return Err(AuctionError::InvalidState.into());
    }

    // Confirm we're looking at the real SPL account for this bidder.
    let bidder_pot = BidderPot::from_account_info(accounts.bidder_pot)?;
    if bidder_pot.bidder_pot != *accounts.bidder_pot_token.key {
        return Err(AuctionError::BidderPotTokenAccountOwnerMismatch.into());
    }

    // Transfer SPL bid balance back to the user.
    let account: Account = Account::unpack_from_slice(&accounts.bidder_pot_token.data.borrow())?;
    spl_token_transfer(TokenTransferParams {
        source: accounts.bidder_pot_token.clone(),
        destination: accounts.bidder_token.clone(),
        authority: accounts.auction.clone(),
        authority_signer_seeds: auction_seeds,
        token_program: accounts.token_program.clone(),
        amount: account.amount,
    })?;

    // Update Metadata
    let metadata = BidderMetadata::from_account_info(accounts.bidder_meta)?;
    let already_cancelled = metadata.cancelled;
    BidderMetadata {
        cancelled: true,
        ..metadata
    }
    .serialize(&mut *accounts.bidder_meta.data.borrow_mut())?;

    // Update Auction

    if auction.state != AuctionState::Ended {
        // Once ended we want uncancelled bids to retain it's pre-ending count
        assert_derivation(
            program_id,
            accounts.auction_extended,
            &[
                PREFIX.as_bytes(),
                program_id.as_ref(),
                args.resource.as_ref(),
                EXTENDED.as_bytes(),
            ],
        )?;
        let mut auction_extended =
            AuctionDataExtended::from_account_info(accounts.auction_extended)?;

        msg!("Already cancelled is {:?}", already_cancelled);

        if !already_cancelled && auction_extended.total_uncancelled_bids > 0 {
            auction_extended.total_uncancelled_bids = auction_extended
                .total_uncancelled_bids
                .checked_sub(1)
                .ok_or(AuctionError::NumericalOverflowError)?;
        }
        auction_extended.serialize(&mut *accounts.auction_extended.data.borrow_mut())?;

        // Only cancel the bid if the auction has not ended yet
        auction.bid_state.cancel_bid(*accounts.bidder.key);
        auction.serialize(&mut *accounts.auction.data.borrow_mut())?;
    }

    Ok(())
}

```
</details>


#### 6. `EndAuction(EndAuctionArgs)` Ends an auction, regardless of end timing conditions
	
**Account Info:**
(No info in comment)
1. Authority Key
2. Auction Account
3. Clock sysvar
	
**Create Instruction(test purpose):**
<details>
	
```rust=
pub fn end_auction_instruction(
    program_id: Pubkey,
    authority_pubkey: Pubkey,
    args: EndAuctionArgs,
) -> Instruction {
    // Derive Auction Key
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        args.resource.as_ref(),
    ];
    let (auction_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(authority_pubkey, true),
            AccountMeta::new(auction_pubkey, false),
            AccountMeta::new_readonly(sysvar::clock::id(), false),
        ],
        data: AuctionInstruction::EndAuction(args).try_to_vec().unwrap(),
    }
}
```	

</details>	
	
**Process:**

<details>

```rust=
use crate::{
    errors::AuctionError,
    processor::{AuctionData, AuctionState, Bid, BidState, PriceFloor, WinnerLimit},
    utils::{assert_derivation, assert_owned_by, assert_signer, create_or_allocate_account_raw},
    PREFIX,
};

use {
    borsh::{BorshDeserialize, BorshSerialize},
    solana_program::{
        account_info::{next_account_info, AccountInfo},
        clock::Clock,
        entrypoint::ProgramResult,
        hash, msg,
        program_error::ProgramError,
        pubkey::Pubkey,
        sysvar::Sysvar,
    },
    std::mem,
};

type Price = u64;
type Salt = u64;
type Revealer = (Price, Salt);

#[repr(C)]
#[derive(Clone, BorshSerialize, BorshDeserialize, PartialEq)]
pub struct EndAuctionArgs {
    /// The resource being auctioned. See AuctionData.
    pub resource: Pubkey,
    /// If the auction was blinded, a revealing price must be specified to release the auction
    /// winnings.
    pub reveal: Option<Revealer>,
}

struct Accounts<'a, 'b: 'a> {
    authority: &'a AccountInfo<'b>,
    auction: &'a AccountInfo<'b>,
    clock_sysvar: &'a AccountInfo<'b>,
}

fn parse_accounts<'a, 'b: 'a>(
    program_id: &Pubkey,
    accounts: &'a [AccountInfo<'b>],
) -> Result<Accounts<'a, 'b>, ProgramError> {
    let account_iter = &mut accounts.iter();
    let accounts = Accounts {
        authority: next_account_info(account_iter)?,
        auction: next_account_info(account_iter)?,
        clock_sysvar: next_account_info(account_iter)?,
    };
    assert_owned_by(accounts.auction, program_id)?;
    assert_signer(accounts.authority)?;
    Ok(accounts)
}

fn reveal(price_floor: PriceFloor, revealer: Option<Revealer>) -> Result<PriceFloor, ProgramError> {
    // If the price floor was blinded, we update it.
    if let PriceFloor::BlindedPrice(blinded) = price_floor {
        // If the hash matches, update the price to the actual minimum.
        if let Some(reveal) = revealer {
            let reveal_hash = hash::hashv(&[&reveal.0.to_be_bytes(), &reveal.1.to_be_bytes()]);
            if reveal_hash != blinded {
                return Err(AuctionError::InvalidReveal.into());
            }
            Ok(PriceFloor::MinimumPrice([reveal.0, 0, 0, 0]))
        } else {
            return Err(AuctionError::MustReveal.into());
        }
    } else {
        // No change needed in the else case.
        Ok(price_floor)
    }
}

pub fn end_auction<'a, 'b: 'a>(
    program_id: &Pubkey,
    accounts: &'a [AccountInfo<'b>],
    args: EndAuctionArgs,
) -> ProgramResult {
    msg!("+ Processing EndAuction");
    let accounts = parse_accounts(program_id, accounts)?;
    let clock = Clock::from_account_info(accounts.clock_sysvar)?;

    assert_derivation(
        program_id,
        accounts.auction,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            &args.resource.as_ref(),
        ],
    )?;

    // End auction.
    let mut auction = AuctionData::from_account_info(accounts.auction)?;

    // Check authority is correct.
    if auction.authority != *accounts.authority.key {
        return Err(AuctionError::InvalidAuthority.into());
    }

    // As long as it hasn't already ended.
    if auction.ended_at.is_some() {
        return Err(AuctionError::AuctionTransitionInvalid.into());
    }

    AuctionData {
        ended_at: Some(clock.unix_timestamp),
        state: auction.state.end()?,
        price_floor: reveal(auction.price_floor, args.reveal)?,
        ..auction
    }
    .serialize(&mut *accounts.auction.data.borrow_mut())?;

    Ok(())
}

```
	
</details>
	

[Question]

1. Function `reveal` - price floor, not complete understand
2. Alreay end check
In Auction Data
```rust=
    /// Slot time the auction was officially ended by.
    pub ended_at: Option<UnixTimestamp>,
    /// End time is the cut-off point that the auction is forced to end by.
    pub end_auction_at: Option<UnixTimestamp>,
```
But in End auction: corebuild-rust/auction/program/src/processor/end_auction.rs
```rust=103
    // As long as it hasn't already ended.
    if auction.ended_at.is_some() {
        return Err(AuctionError::AuctionTransitionInvalid.into());
    }
```
`end_auction_at` is never checked? or it's a misleading naming here, it seems never used in the auction. 

	

#### 7. `ClaimBid(ClaimBidArgs)` Move SPL tokens from winning bid to the destination account
	
**Account Info:**
	
0. `[writable]` The destination account
1. `[writable]` The bidder pot token account
2. `[]` The bidder pot pda account [seed of ['auction', program_id, auction key, bidder key]]
3. `[signer]` The authority on the auction
4. `[]` The auction
5. `[]` The bidder wallet
6. `[]` Token mint of the auction
7. `[]` Clock sysvar
8. `[]` Token program
**Create Instruction(test purpose):**

<details>
	
```rust=
pub fn claim_bid_instruction(
    program_id: Pubkey,
    destination_pubkey: Pubkey,
    authority_pubkey: Pubkey,
    bidder_pubkey: Pubkey,
    bidder_pot_token_pubkey: Pubkey,
    token_mint_pubkey: Pubkey,
    args: ClaimBidArgs,
) -> Instruction {
    // Derive Auction Key
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        args.resource.as_ref(),
    ];
    let (auction_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    // Derive Bidder Pot
    let seeds = &[
        PREFIX.as_bytes(),
        &program_id.as_ref(),
        auction_pubkey.as_ref(),
        bidder_pubkey.as_ref(),
    ];
    let (bidder_pot_pubkey, _) = Pubkey::find_program_address(seeds, &program_id);

    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(destination_pubkey, false),
            AccountMeta::new(bidder_pot_token_pubkey, false),
            AccountMeta::new(bidder_pot_pubkey, false),
            AccountMeta::new_readonly(authority_pubkey, true),
            AccountMeta::new_readonly(auction_pubkey, false),
            AccountMeta::new_readonly(bidder_pubkey, false),
            AccountMeta::new_readonly(token_mint_pubkey, false),
            AccountMeta::new_readonly(sysvar::clock::id(), false),
            AccountMeta::new_readonly(spl_token::id(), false),
        ],
        data: AuctionInstruction::ClaimBid(args).try_to_vec().unwrap(),
    }
}
```
</details>
	
**Process:**

<details>
	
```rust=
pub fn claim_bid(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    args: ClaimBidArgs,
) -> ProgramResult {
    msg!("+ Processing ClaimBid");
    let accounts = parse_accounts(program_id, accounts)?;
    let clock = Clock::from_account_info(accounts.clock_sysvar)?;

    // The account within the pot must be owned by us.
    let actual_account: Account = assert_initialized(accounts.bidder_pot_token)?;
    if actual_account.owner != *accounts.auction.key {
        return Err(AuctionError::BidderPotTokenAccountOwnerMismatch.into());
    }

    // Derive and load Auction.
    let auction_bump = assert_derivation(
        program_id,
        accounts.auction,
        &[
            PREFIX.as_bytes(),
            program_id.as_ref(),
            args.resource.as_ref(),
        ],
    )?;

    let auction_seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        args.resource.as_ref(),
        &[auction_bump],
    ];

    // Load the auction and verify this bid is valid.
    let auction = AuctionData::from_account_info(accounts.auction)?;

    if auction.authority != *accounts.authority.key {
        return Err(AuctionError::InvalidAuthority.into());
    }

    // User must have won the auction in order to claim their funds. Check early as the rest of the
    // checks will be for nothing otherwise.
    if auction.is_winner(accounts.bidder.key).is_none() {
        msg!("User {:?} is not winner", accounts.bidder.key);
        return Err(AuctionError::InvalidState.into());
    }

    // Auction must have ended.
    if !auction.ended(clock.unix_timestamp)? {
        return Err(AuctionError::InvalidState.into());
    }

    // The mint provided in this claim must match the one the auction was initialized with.
    if auction.token_mint != *accounts.mint.key {
        return Err(AuctionError::IncorrectMint.into());
    }

    // Derive Pot address, this account wraps/holds an SPL account to transfer tokens into.
    let pot_seeds = [
        PREFIX.as_bytes(),
        program_id.as_ref(),
        accounts.auction.key.as_ref(),
        accounts.bidder.key.as_ref(),
    ];

    let pot_bump = assert_derivation(program_id, accounts.bidder_pot, &pot_seeds)?;

    let bump_authority_seeds = &[
        PREFIX.as_bytes(),
        program_id.as_ref(),
        accounts.auction.key.as_ref(),
        accounts.bidder.key.as_ref(),
        &[pot_bump],
    ];

    // If the bidder pot account is empty, this bid is invalid.
    if accounts.bidder_pot.data_is_empty() {
        return Err(AuctionError::BidderPotDoesNotExist.into());
    }

    // Confirm we're looking at the real SPL account for this bidder.
    let mut bidder_pot = BidderPot::from_account_info(accounts.bidder_pot)?;
    if bidder_pot.bidder_pot != *accounts.bidder_pot_token.key {
        return Err(AuctionError::BidderPotTokenAccountOwnerMismatch.into());
    }

    // Transfer SPL bid balance back to the user.
    spl_token_transfer(TokenTransferParams {
        source: accounts.bidder_pot_token.clone(),
        destination: accounts.destination.clone(),
        authority: accounts.auction.clone(),
        authority_signer_seeds: auction_seeds,
        token_program: accounts.token_program.clone(),
        amount: actual_account.amount,
    })?;

    bidder_pot.emptied = true;
    bidder_pot.serialize(&mut *accounts.bidder_pot.data.borrow_mut())?;

    Ok(())
}

```
</details>

[Question]

1. `Winner` logic not complete understand
2. Claim bid(the winer) will get deposit back? Or it's a misleading comment(not back to user but to a destination).
```rust=167
    // Transfer SPL bid balance back to the user.
    spl_token_transfer(TokenTransferParams {
        source: accounts.bidder_pot_token.clone(),
        destination: accounts.destination.clone(),
        authority: accounts.auction.clone(),
        authority_signer_seeds: auction_seeds,
        token_program: accounts.token_program.clone(),
        amount: actual_account.amount,
    })?;
```
	
	

## Metaplex
### Structure

#### 1. `InitAuctionManager(AuctionManagerSettings)` Initializes an Auction Manager
	
**Account Info:**
0. `[writable]` Uninitialized, unallocated auction manager account with pda of ['metaplex', auction_key from auction referenced below]
1. `[]` Combined vault account with authority set to auction manager account (this will be checked)
        Note in addition that this vault account should have authority set to this program's pda of ['metaplex', auction_key]
2. `[]` Auction with auctioned item being set to the vault given and authority set to this program's pda of ['metaplex', auction_key]
3. `[]` Authority for the Auction Manager
4. `[signer]` Payer
5. `[]` Accept payment account of same token mint as the auction for taking payment for open editions, owner should be auction manager key
6. `[]` Store that this auction manager will belong to
7. `[]` System sysvar    
8. `[]` Rent sysvar
	
**Create Instruction(test purpose):**	

<details>

```rust
/// Creates an InitAuctionManager instruction
#[allow(clippy::too_many_arguments)]
pub fn create_init_auction_manager_instruction(
    program_id: Pubkey,
    auction_manager: Pubkey,
    vault: Pubkey,
    auction: Pubkey,
    auction_manager_authority: Pubkey,
    payer: Pubkey,
    accept_payment_account_key: Pubkey,
    store: Pubkey,
    settings: AuctionManagerSettings,
) -> Instruction {
    Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(auction_manager, false),
            AccountMeta::new_readonly(vault, false),
            AccountMeta::new_readonly(auction, false),
            AccountMeta::new_readonly(auction_manager_authority, false),
            AccountMeta::new_readonly(payer, true),
            AccountMeta::new_readonly(accept_payment_account_key, false),
            AccountMeta::new_readonly(store, false),
            AccountMeta::new_readonly(solana_program::system_program::id(), false),
            AccountMeta::new_readonly(sysvar::rent::id(), false),
        ],
        data: MetaplexInstruction::InitAuctionManager(settings)
            .try_to_vec()
            .unwrap(),
    }
}
```
	
</details>
	
**Process:**


	
	
#### 2. `ValidateSafetyDepositBox` Validates that a given safety deposit box has in it contents that match the expected WinningConfig in the auction manager.
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	

#### 3. `DeprecatedRedeemBid` 
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
	

#### 4. `RedeemFullRightsTransferBid`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	


#### 5. `DeprecatedRedeemParticipationBid`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	

#### 6. `StartAuction`
	
**Account Info:**
0. `[writable]` Auction manager
1. `[writable]` Auction
3. `[signer]` Auction manager authority
4. `[]` Store key
5. `[]` Auction program
6. `[]` Clock sysvar
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 7. `ClaimBid` 
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**


#### 8. `EmptyPaymentAccount(EmptyPaymentAccountArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 9. `SetStore(SetStoreArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 10. `SetWhitelistedCreator(SetWhitelistedCreatorArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 11. `DeprecatedValidateParticipation`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 12. `DeprecatedPopulateParticipationPrintingAccount`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 13. `RedeemUnusedWinningConfigItemsAsAuctioneer(RedeemUnusedWinningConfigItemsAsAuctioneerArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 14. `DecommissionAuctionManager`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 15. `RedeemPrintingV2Bid(RedeemPrintingV2BidArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 16. `WithdrawMasterEdition`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 17. `RedeemParticipationBidV2`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
## Token Metadata
[Question] Deprecated intructions??
	
### Structure

	
### Instructions
#### 1. `CreateMetadataAccount(CreateMetadataAccountArgs)` Create Metadata object
	
**Account Info:**
	
0. `[writable]`  Metadata key (pda of ['metadata', program id, mint id])
1. `[]` Mint of token asset
2. `[signer]` Mint authority
3. `[signer]` payer
4. `[]` update authority info
5. `[]` System program
6. `[]` Rent info
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 2.`UpdateMetadataAccount(UpdateMetadataAccountArgs)` Update a Metadta
	
**Account Info:**
	
0. `[writable]` Metadata account
1. `[signer]` Update authority key
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 3.`DeprecatedCreateMasterEdition(CreateMasterEditionArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 4.`DeprecatedMintNewEditionFromMasterEditionViaPrintingToken`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 5.`UpdatePrimarySaleHappenedViaToken`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
	
#### 6.`DeprecatedSetReservationList(SetReservationListArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
#### 7.`DeprecatedCreateReservationList`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
#### 8.`SignMetadata`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 9.`DeprecatedMintPrintingTokensViaToken(MintPrintingTokensViaTokenArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
#### 10. `DeprecatedMintPrintingTokens(MintPrintingTokensViaTokenArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**
	
#### 11. `CreateMasterEdition(CreateMasterEditionArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 12. `MintNewEditionFromMasterEditionViaToken(MintNewEditionFromMasterEditionViaTokenArgs)`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 13. `ConvertMasterEditionV1ToV2`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

#### 14. `ConvertMasterEditionV1ToV2`
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**

[Question]

1. V1 to V2 authority check???

```rust=
pub struct MasterEditionV1 {
    pub key: Key,

    pub supply: u64,

    pub max_supply: Option<u64>,

    /// Can be used to mint tokens that give one-time permission to mint a single limited edition.
    pub printing_mint: Pubkey,

    /// If you don't know how many printing tokens you are going to need, but you do know
    /// you are going to need some amount in the future, you can use a token from this mint.
    /// Coming back to token metadata with one of these tokens allows you to mint (one time)
    /// any number of printing tokens you want. This is used for instance by Auction Manager
    /// with participation NFTs, where we dont know how many people will bid and need participation
    /// printing tokens to redeem, so we give it ONE of these tokens to use after the auction is over,
    /// because when the auction begins we just dont know how many printing tokens we will need,
    /// but at the end we will. At the end it then burns this token with token-metadata to
    /// get the printing tokens it needs to give to bidders. Each bidder then redeems a printing token
    /// to get their limited editions.
    pub one_time_printing_authorization_mint: Pubkey,
}
```
	
```rust=
pub struct MasterEditionV2 {
    pub key: Key,

    pub supply: u64,

    pub max_supply: Option<u64>,
}
```

2. edition check:
like this: /rust/token-metadata/test/src/main.rs
```rust=147
 master_edition_account.data[0] == Key::MasterEditionV2
```

## Token Vault
### Structure
#### `Vault` Structure
```rust=
#[repr(C)]
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct Vault {
    pub key: Key,
    /// Store token program used
    pub token_program: Pubkey,
    /// Mint that produces the fractional shares
    pub fraction_mint: Pubkey,
    /// Authority who can make changes to the vault
    pub authority: Pubkey,
    /// treasury where fractional shares are held for redemption by authority
    pub fraction_treasury: Pubkey,
    /// treasury where monies are held for fractional share holders to redeem(burn) shares once buyout is made
    pub redeem_treasury: Pubkey,
    /// Can authority mint more shares from fraction_mint after activation
    pub allow_further_share_creation: bool,

    /// Must point at an ExternalPriceAccount, which gives permission and price for buyout.
    pub pricing_lookup_address: Pubkey,
    /// In inactive state, we use this to set the order key on Safety Deposit Boxes being added and
    /// then we increment it and save so the next safety deposit box gets the next number.
    /// In the Combined state during token redemption by authority, we use it as a decrementing counter each time
    /// The authority of the vault withdrawals a Safety Deposit contents to count down how many
    /// are left to be opened and closed down. Once this hits zero, and the fraction mint has zero shares,
    /// then we can deactivate the vault.
    pub token_type_count: u8,
    pub state: VaultState,

    /// Once combination happens, we copy price per share to vault so that if something nefarious happens
    /// to external price account, like price change, we still have the math 'saved' for use in our calcs
    pub locked_price_per_share: u64,
}
```

####  `SafetyDepositBox` Structure
```rust=
#[repr(C)]
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct SafetyDepositBox {
    // Please note if you change this struct, be careful as we read directly off it
    // in Metaplex to avoid serialization costs...
    /// Each token type in a vault has it's own box that contains it's mint and a look-back
    pub key: Key,
    /// Key pointing to the parent vault
    pub vault: Pubkey,
    /// This particular token's mint
    pub token_mint: Pubkey,
    /// Account that stores the tokens under management
    pub store: Pubkey,
    /// the order in the array of registries
    pub order: u8,
}
```

#### `ExternalPriceAccount` Structure
```rust=
#[repr(C)]
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct ExternalPriceAccount {
    pub key: Key,
    pub price_per_share: u64,
    /// Mint of the currency we are pricing the shares against, should be same as redeem_treasury.
    /// Most likely will be USDC mint most of the time.
    pub price_mint: Pubkey,
    /// Whether or not combination has been allowed for this vault.
    pub allowed_to_combine: bool,
}

```
	
### Instructions
#### 1.
	
**Account Info:**
**Create Instruction(test purpose):**	
**Process:**	