use crate::{
error::MetaplexError,
state::{
Key, PrintingV2CalculationCheckReturn, PrintingV2CalculationChecks, WinningConfigType,
MAX_PRIZE_TRACKING_TICKET_SIZE, PREFIX,
},
utils::{
assert_derivation, assert_is_ata, assert_owned_by, common_redeem_checks,
common_redeem_finish, create_or_allocate_account_raw, get_amount_from_token_account,
CommonRedeemCheckArgs, CommonRedeemFinishArgs, CommonRedeemReturn,
},
};
use arrayref::{array_mut_ref, array_ref, mut_array_refs};
use mpl_auction::processor::AuctionData;
#[allow(deprecated)]
use mpl_token_metadata::{
instruction::mint_edition_from_master_edition_via_vault_proxy,
utils::get_supply_off_master_edition,
};
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::ProgramResult,
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
};
#[allow(clippy::too_many_arguments)]
pub fn mint_edition<'a>(
token_metadata_program_info: &AccountInfo<'a>,
token_vault_program_info: &AccountInfo<'a>,
new_metadata_account_info: &AccountInfo<'a>,
new_edition_account_info: &AccountInfo<'a>,
master_edition_account_info: &AccountInfo<'a>,
edition_marker_info: &AccountInfo<'a>,
mint_info: &AccountInfo<'a>,
mint_authority_info: &AccountInfo<'a>,
payer_info: &AccountInfo<'a>,
auction_manager_info: &AccountInfo<'a>,
safety_deposit_token_store_info: &AccountInfo<'a>,
safety_deposit_box_info: &AccountInfo<'a>,
vault_info: &AccountInfo<'a>,
bidder_info: &AccountInfo<'a>,
metadata_account_info: &AccountInfo<'a>,
token_program_info: &AccountInfo<'a>,
system_program_info: &AccountInfo<'a>,
rent_info: &AccountInfo<'a>,
actual_edition: u64,
signer_seeds: &[&[u8]],
) -> ProgramResult {
#[allow(deprecated)]
invoke_signed(
&mint_edition_from_master_edition_via_vault_proxy(
*token_metadata_program_info.key,
*new_metadata_account_info.key,
*new_edition_account_info.key,
*master_edition_account_info.key,
*mint_info.key,
*edition_marker_info.key,
*mint_authority_info.key,
*payer_info.key,
*auction_manager_info.key,
*safety_deposit_token_store_info.key,
*safety_deposit_box_info.key,
*vault_info.key,
*bidder_info.key,
*metadata_account_info.key,
*token_program_info.key,
*token_vault_program_info.key,
actual_edition,
),
&[
token_metadata_program_info.clone(),
token_vault_program_info.clone(),
new_metadata_account_info.clone(),
new_edition_account_info.clone(),
master_edition_account_info.clone(),
edition_marker_info.clone(),
mint_info.clone(),
mint_authority_info.clone(),
payer_info.clone(),
auction_manager_info.clone(),
safety_deposit_token_store_info.clone(),
safety_deposit_box_info.clone(),
vault_info.clone(),
bidder_info.clone(),
metadata_account_info.clone(),
token_program_info.clone(),
system_program_info.clone(),
rent_info.clone(),
],
&[&signer_seeds],
)?;
Ok(())
}
pub fn create_or_update_prize_tracking<'a>(
program_id: &'a Pubkey,
auction_manager_info: &AccountInfo<'a>,
prize_tracking_ticket_info: &AccountInfo<'a>,
metadata_account_info: &AccountInfo<'a>,
payer_info: &AccountInfo<'a>,
rent_info: &AccountInfo<'a>,
system_info: &AccountInfo<'a>,
master_edition_account_info: &AccountInfo<'a>,
expected_redemptions: u64,
) -> Result<u64, ProgramError> {
let metadata_data = metadata_account_info.data.borrow();
let metadata_mint = Pubkey::new_from_array(*array_ref![metadata_data, 33, 32]);
let bump = assert_derivation(
program_id,
prize_tracking_ticket_info,
&[
PREFIX.as_bytes(),
program_id.as_ref(),
auction_manager_info.key.as_ref(),
metadata_mint.as_ref(),
],
)?;
let supply_snapshot: u64;
if prize_tracking_ticket_info.data_is_empty() {
create_or_allocate_account_raw(
*program_id,
prize_tracking_ticket_info,
rent_info,
system_info,
payer_info,
MAX_PRIZE_TRACKING_TICKET_SIZE,
&[
PREFIX.as_bytes(),
program_id.as_ref(),
auction_manager_info.key.as_ref(),
metadata_mint.as_ref(),
&[bump],
],
)?;
let data = &mut prize_tracking_ticket_info.data.borrow_mut();
let output = array_mut_ref![data, 0, MAX_PRIZE_TRACKING_TICKET_SIZE];
let (key, metadata, supply_snapshot_ptr, expected_redemptions_ptr, redemptions, _padding) =
mut_array_refs![output, 1, 32, 8, 8, 8, 50];
*key = [Key::PrizeTrackingTicketV1 as u8];
metadata.copy_from_slice(metadata_account_info.key.as_ref());
supply_snapshot = get_supply_off_master_edition(master_edition_account_info)?;
*supply_snapshot_ptr = supply_snapshot.to_le_bytes();
*redemptions = 1u64.to_le_bytes();
*expected_redemptions_ptr = expected_redemptions.to_le_bytes();
} else {
let data = &mut prize_tracking_ticket_info.data.borrow_mut();
let output = array_mut_ref![data, 0, MAX_PRIZE_TRACKING_TICKET_SIZE];
let (_key, _metadata, supply_snapshot_ptr, _expected_redemptions, redemptions, _padding) =
mut_array_refs![output, 1, 32, 8, 8, 8, 50];
supply_snapshot = u64::from_le_bytes(*supply_snapshot_ptr);
let next_redemptions = u64::from_le_bytes(*redemptions)
.checked_add(1)
.ok_or(MetaplexError::NumericalOverflowError)?;
*redemptions = next_redemptions.to_le_bytes();
}
Ok(supply_snapshot)
}
pub fn process_redeem_printing_v2_bid<'a>(
program_id: &'a Pubkey,
accounts: &'a [AccountInfo<'a>],
edition_offset: u64,
user_provided_win_index: u64,
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let auction_manager_info = next_account_info(account_info_iter)?;
let safety_deposit_token_store_info = next_account_info(account_info_iter)?;
let new_edition_token_account_info = next_account_info(account_info_iter)?;
let bid_redemption_info = next_account_info(account_info_iter)?;
let safety_deposit_info = next_account_info(account_info_iter)?;
let vault_info = next_account_info(account_info_iter)?;
let safety_deposit_config_info = next_account_info(account_info_iter)?;
let auction_info = next_account_info(account_info_iter)?;
let bidder_metadata_info = next_account_info(account_info_iter)?;
let bidder_info = next_account_info(account_info_iter)?;
let payer_info = next_account_info(account_info_iter)?;
let token_program_info = next_account_info(account_info_iter)?;
let token_vault_program_info = next_account_info(account_info_iter)?;
let token_metadata_program_info = next_account_info(account_info_iter)?;
let store_info = next_account_info(account_info_iter)?;
let system_info = next_account_info(account_info_iter)?;
let rent_info = next_account_info(account_info_iter)?;
let prize_tracking_ticket_info = next_account_info(account_info_iter)?;
let new_metadata_account_info = next_account_info(account_info_iter)?;
let new_edition_account_info = next_account_info(account_info_iter)?;
let master_edition_account_info = next_account_info(account_info_iter)?;
let mint_info = next_account_info(account_info_iter)?;
let edition_marker_info = next_account_info(account_info_iter)?;
let mint_authority_info = next_account_info(account_info_iter)?;
let metadata_account_info = next_account_info(account_info_iter)?;
let auction_extended_info = next_account_info(account_info_iter).ok();
let new_edition_account_amount = get_amount_from_token_account(new_edition_token_account_info)?;
assert_is_ata(
new_edition_token_account_info,
bidder_info.key,
mint_info.key,
)?;
if new_edition_account_amount != 1 {
return Err(MetaplexError::ProvidedAccountDoesNotContainOneToken.into());
}
let CommonRedeemReturn {
auction_manager,
redemption_bump_seed,
cancelled,
rent: _rent,
win_index,
token_metadata_program,
} = common_redeem_checks(CommonRedeemCheckArgs {
program_id,
auction_manager_info,
safety_deposit_token_store_info,
destination_info: new_edition_token_account_info,
bid_redemption_info,
safety_deposit_info,
vault_info,
auction_info,
auction_extended_info,
bidder_metadata_info,
bidder_info,
token_program_info,
token_vault_program_info,
token_metadata_program_info,
store_info,
rent_info,
safety_deposit_config_info: Some(safety_deposit_config_info),
is_participation: false,
user_provided_win_index: Some(Some(user_provided_win_index as usize)),
overwrite_win_index: None,
assert_bidder_signer: false,
ignore_bid_redeemed_item_check: true,
})?;
assert_owned_by(metadata_account_info, &token_metadata_program)?;
let mut winning_item_index = None;
if !cancelled {
if let Some(winning_index) = win_index {
let PrintingV2CalculationCheckReturn {
expected_redemptions,
winning_config_type,
winning_config_item_index,
} = auction_manager.printing_v2_calculation_checks(PrintingV2CalculationChecks {
safety_deposit_info,
winning_index,
auction_manager_v1_ignore_claim: true,
winners: AuctionData::get_num_winners(auction_info),
short_circuit_total: !prize_tracking_ticket_info.data_is_empty(),
safety_deposit_config_info: Some(safety_deposit_config_info),
edition_offset,
})?;
winning_item_index = winning_config_item_index;
if winning_config_type != WinningConfigType::PrintingV2 {
return Err(MetaplexError::WrongBidEndpointForPrize.into());
}
let auction_manager_bump = assert_derivation(
program_id,
auction_manager_info,
&[PREFIX.as_bytes(), auction_info.key.as_ref()],
)?;
let supply_snapshot = create_or_update_prize_tracking(
program_id,
auction_manager_info,
prize_tracking_ticket_info,
metadata_account_info,
payer_info,
rent_info,
system_info,
master_edition_account_info,
expected_redemptions,
)?;
let actual_edition = edition_offset
.checked_add(supply_snapshot)
.ok_or(MetaplexError::NumericalOverflowError)?;
let signer_seeds = &[
PREFIX.as_bytes(),
auction_info.key.as_ref(),
&[auction_manager_bump],
];
mint_edition(
token_metadata_program_info,
token_vault_program_info,
new_metadata_account_info,
new_edition_account_info,
master_edition_account_info,
edition_marker_info,
mint_info,
mint_authority_info,
payer_info,
auction_manager_info,
safety_deposit_token_store_info,
safety_deposit_info,
vault_info,
bidder_info,
metadata_account_info,
token_program_info,
system_info,
rent_info,
actual_edition,
signer_seeds,
)?;
}
};
common_redeem_finish(CommonRedeemFinishArgs {
program_id,
auction_manager,
auction_manager_info,
bidder_metadata_info,
rent_info,
system_info,
payer_info,
bid_redemption_info,
vault_info,
safety_deposit_config_info: Some(safety_deposit_config_info),
redemption_bump_seed,
winning_index: win_index,
bid_redeemed: true,
participation_redeemed: false,
winning_item_index,
overwrite_win_index: None,
})?;
Ok(())
}