From e4c670bec9ef14136de8090a60b244d0cbeeedbf Mon Sep 17 00:00:00 2001 From: Vadim Date: Wed, 21 Jul 2021 14:23:40 +0300 Subject: [PATCH] Add instant_sale_price check to ClaimBid instruction --- rust/auction/program/src/instruction.rs | 9 ++++++ .../program/src/processor/claim_bid.rs | 32 ++++++++++++++++--- .../program/src/processor/claim_bid.rs | 5 +++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/rust/auction/program/src/instruction.rs b/rust/auction/program/src/instruction.rs index f9d599a..d5c8f8f 100644 --- a/rust/auction/program/src/instruction.rs +++ b/rust/auction/program/src/instruction.rs @@ -338,6 +338,14 @@ pub fn claim_bid_instruction( ]; let (bidder_pot_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![ @@ -346,6 +354,7 @@ pub fn claim_bid_instruction( AccountMeta::new(bidder_pot_pubkey, false), AccountMeta::new_readonly(authority_pubkey, true), AccountMeta::new_readonly(auction_pubkey, false), + AccountMeta::new_readonly(auction_extended_pubkey, false), AccountMeta::new_readonly(bidder_pubkey, false), AccountMeta::new_readonly(token_mint_pubkey, false), AccountMeta::new_readonly(sysvar::clock::id(), false), diff --git a/rust/auction/program/src/processor/claim_bid.rs b/rust/auction/program/src/processor/claim_bid.rs index 1e1e677..229820f 100755 --- a/rust/auction/program/src/processor/claim_bid.rs +++ b/rust/auction/program/src/processor/claim_bid.rs @@ -3,13 +3,14 @@ use crate::{ errors::AuctionError, - processor::{AuctionData, BidderMetadata, BidderPot}, + processor::{AuctionData, AuctionDataExtended, BidderMetadata, BidderPot}, utils::{ assert_derivation, assert_initialized, assert_owned_by, assert_signer, assert_token_program_matches_package, create_or_allocate_account_raw, spl_token_transfer, TokenTransferParams, }, PREFIX, + EXTENDED, }; use { @@ -40,6 +41,7 @@ struct Accounts<'a, 'b: 'a> { bidder_pot: &'a AccountInfo<'b>, authority: &'a AccountInfo<'b>, auction: &'a AccountInfo<'b>, + auction_extended: &'a AccountInfo<'b>, bidder: &'a AccountInfo<'b>, mint: &'a AccountInfo<'b>, clock_sysvar: &'a AccountInfo<'b>, @@ -57,6 +59,7 @@ fn parse_accounts<'a, 'b: 'a>( bidder_pot: next_account_info(account_iter)?, authority: next_account_info(account_iter)?, auction: next_account_info(account_iter)?, + auction_extended: next_account_info(account_iter)?, bidder: next_account_info(account_iter)?, mint: next_account_info(account_iter)?, clock_sysvar: next_account_info(account_iter)?, @@ -64,6 +67,7 @@ fn parse_accounts<'a, 'b: 'a>( }; assert_owned_by(accounts.auction, program_id)?; + assert_owned_by(accounts.auction_extended, program_id)?; assert_owned_by(accounts.mint, &spl_token::id())?; assert_owned_by(accounts.destination, &spl_token::id())?; assert_owned_by(accounts.bidder_pot_token, &spl_token::id())?; @@ -114,20 +118,40 @@ pub fn claim_bid( // Load the auction and verify this bid is valid. let auction = AuctionData::from_account_info(accounts.auction)?; + 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)?; + 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() { + let bid_index = auction.is_winner(accounts.bidder.key); + if bid_index.is_none() { msg!("User {:?} is not winner", accounts.bidder.key); return Err(AuctionError::InvalidState.into()); } - // Auction must have ended. + // Auction either must have ended or bidder pay instant_sale_price if !auction.ended(clock.unix_timestamp)? { - return Err(AuctionError::InvalidState.into()); + if let Some(instant_sale_price) = auction_extended.instant_sale_price { + if auction.bid_state.amount(bid_index.unwrap()) < instant_sale_price { + return Err(AuctionError::InvalidState.into()); + } + } else { + return Err(AuctionError::InvalidState.into()); + } } // The mint provided in this claim must match the one the auction was initialized with. diff --git a/rust/metaplex/program/src/processor/claim_bid.rs b/rust/metaplex/program/src/processor/claim_bid.rs index 6301bff..b632cd6 100644 --- a/rust/metaplex/program/src/processor/claim_bid.rs +++ b/rust/metaplex/program/src/processor/claim_bid.rs @@ -21,6 +21,7 @@ use { pub fn issue_claim_bid<'a>( auction_program: AccountInfo<'a>, auction: AccountInfo<'a>, + auction_extended: AccountInfo<'a>, accept_payment: AccountInfo<'a>, authority: AccountInfo<'a>, bidder: AccountInfo<'a>, @@ -46,6 +47,7 @@ pub fn issue_claim_bid<'a>( auction_program, authority, auction, + auction_extended, clock, token_mint, bidder, @@ -67,6 +69,7 @@ pub fn process_claim_bid(program_id: &Pubkey, accounts: &[AccountInfo]) -> Progr let bidder_pot_info = next_account_info(account_info_iter)?; let auction_manager_info = next_account_info(account_info_iter)?; let auction_info = next_account_info(account_info_iter)?; + let auction_extended_info = next_account_info(account_info_iter)?; let bidder_info = next_account_info(account_info_iter)?; let token_mint_info = next_account_info(account_info_iter)?; let vault_info = next_account_info(account_info_iter)?; @@ -80,6 +83,7 @@ pub fn process_claim_bid(program_id: &Pubkey, accounts: &[AccountInfo]) -> Progr let auction = AuctionData::from_account_info(auction_info)?; assert_owned_by(auction_info, &store.auction_program)?; + assert_owned_by(auction_extended_info, &store.auction_program)?; assert_owned_by(auction_manager_info, program_id)?; assert_owned_by(accept_payment_info, &spl_token::id())?; assert_owned_by(bidder_pot_token_info, &spl_token::id())?; @@ -140,6 +144,7 @@ pub fn process_claim_bid(program_id: &Pubkey, accounts: &[AccountInfo]) -> Progr issue_claim_bid( auction_program_info.clone(), auction_info.clone(), + auction_extended_info.clone(), accept_payment_info.clone(), auction_manager_info.clone(), bidder_info.clone(),