From 2f0335482de533559e7926f4c1cb7e1a0fe7b493 Mon Sep 17 00:00:00 2001 From: Serkan Reis Date: Mon, 20 Jan 2025 22:02:09 +0300 Subject: [PATCH 1/4] Remove min reserve price logic from sudo --- contracts/reserve-auction/src/msg.rs | 6 -- contracts/reserve-auction/src/sudo.rs | 49 +---------- .../src/tests/unit_tests/sudo.rs | 84 +------------------ 3 files changed, 2 insertions(+), 137 deletions(-) diff --git a/contracts/reserve-auction/src/msg.rs b/contracts/reserve-auction/src/msg.rs index 86f3b56e..6ad108ed 100644 --- a/contracts/reserve-auction/src/msg.rs +++ b/contracts/reserve-auction/src/msg.rs @@ -125,10 +125,4 @@ pub enum SudoMsg { halt_buffer_duration: Option, halt_postpone_duration: Option, }, - SetMinReservePrices { - min_reserve_prices: Vec, - }, - UnsetMinReservePrices { - denoms: Vec, - }, } diff --git a/contracts/reserve-auction/src/sudo.rs b/contracts/reserve-auction/src/sudo.rs index 20d00254..6e5281c9 100644 --- a/contracts/reserve-auction/src/sudo.rs +++ b/contracts/reserve-auction/src/sudo.rs @@ -1,7 +1,7 @@ use crate::error::ContractError; use crate::helpers::settle_auction; use crate::msg::SudoMsg; -use crate::state::{auctions, Auction, HaltWindow, CONFIG, HALT_MANAGER, MIN_RESERVE_PRICES}; +use crate::state::{auctions, Auction, HaltWindow, CONFIG, HALT_MANAGER}; use cosmwasm_std::{Addr, Coin, Decimal, DepsMut, Env, Event, Order, StdResult}; use cw_storage_plus::Bound; @@ -40,10 +40,6 @@ pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result { - sudo_set_min_reserve_prices(deps, min_reserve_prices) - } - SudoMsg::UnsetMinReservePrices { denoms } => sudo_unset_min_reserve_prices(deps, denoms), } } @@ -205,46 +201,3 @@ pub fn sudo_update_params( Ok(Response::new().add_event(event)) } - -pub fn sudo_set_min_reserve_prices( - deps: DepsMut, - min_reserve_prices: Vec, -) -> Result { - let mut response = Response::new(); - - for min_reserve_price in min_reserve_prices { - if MIN_RESERVE_PRICES.has(deps.storage, min_reserve_price.denom.clone()) { - return Err(ContractError::InvalidInput( - "found duplicate denom".to_string(), - )); - } - MIN_RESERVE_PRICES.save( - deps.storage, - min_reserve_price.denom.clone(), - &min_reserve_price.amount, - )?; - response = response.add_event( - Event::new("set-min-reserve-price") - .add_attribute("denom", min_reserve_price.denom) - .add_attribute("amount", min_reserve_price.amount), - ); - } - Ok(response) -} - -pub fn sudo_unset_min_reserve_prices( - deps: DepsMut, - denoms: Vec, -) -> Result { - let mut response = Response::new(); - - for denom in denoms { - if !MIN_RESERVE_PRICES.has(deps.storage, denom.clone()) { - return Err(ContractError::InvalidInput("denom not found".to_string())); - } - MIN_RESERVE_PRICES.remove(deps.storage, denom.clone()); - response = - response.add_event(Event::new("unset-min-reserve-price").add_attribute("denom", denom)); - } - Ok(response) -} diff --git a/contracts/reserve-auction/src/tests/unit_tests/sudo.rs b/contracts/reserve-auction/src/tests/unit_tests/sudo.rs index ce23f10a..dc37b4df 100644 --- a/contracts/reserve-auction/src/tests/unit_tests/sudo.rs +++ b/contracts/reserve-auction/src/tests/unit_tests/sudo.rs @@ -18,7 +18,7 @@ use crate::tests::{ setup::{setup_auctions::setup_reserve_auction, setup_minters::standard_minter_template}, }; -use cosmwasm_std::{coin, Coin, Decimal, Uint128}; +use cosmwasm_std::{coin, Decimal, Uint128}; use sg721_base::msg::{CollectionInfoResponse, QueryMsg as Sg721QueryMsg}; use sg_marketplace_common::coin::bps_to_decimal; use sg_marketplace_common::query::QueryOptions; @@ -396,85 +396,3 @@ fn try_sudo_update_params() { "InvalidConfig: extend_duration must be greater than zero" ); } - -#[test] -fn try_sudo_min_reserve_prices() { - let vt = standard_minter_template(1000); - let (mut router, creator, _) = (vt.router, vt.accts.creator, vt.accts.bidder); - let fair_burn = setup_fair_burn(&mut router, creator.clone()); - let reserve_auction = setup_reserve_auction(&mut router, creator, fair_burn).unwrap(); - - setup_block_time(&mut router, GENESIS_MINT_START_TIME, None); - - let coins_response: Vec = router - .wrap() - .query_wasm_smart( - reserve_auction.clone(), - &QueryMsg::MinReservePrices { - query_options: None, - }, - ) - .unwrap(); - - // Duplicate denom throws error - let set_min_reserve_prices_msg = SudoMsg::SetMinReservePrices { - min_reserve_prices: vec![coins_response[0].clone()], - }; - let response = router.wasm_sudo(reserve_auction.clone(), &set_min_reserve_prices_msg); - assert_eq!( - response.unwrap_err().to_string(), - "InvalidInput: found duplicate denom" - ); - - // New denoms can be added - let new_coins = vec![coin(3000000, "uosmo"), coin(4000000, "ujuno")]; - let set_min_reserve_prices_msg = SudoMsg::SetMinReservePrices { - min_reserve_prices: new_coins.clone(), - }; - let response = router.wasm_sudo(reserve_auction.clone(), &set_min_reserve_prices_msg); - assert!(response.is_ok()); - - let next_coins_response: Vec = router - .wrap() - .query_wasm_smart( - reserve_auction.clone(), - &QueryMsg::MinReservePrices { - query_options: None, - }, - ) - .unwrap(); - - let mut expected_coins = coins_response.clone(); - expected_coins.extend(new_coins); - assert_eq!(next_coins_response.len(), expected_coins.len()); - - // Removing non-existent denoms throws error - let unset_min_reserve_prices_msg = SudoMsg::UnsetMinReservePrices { - denoms: vec!["uusd".to_string()], - }; - let response = router.wasm_sudo(reserve_auction.clone(), &unset_min_reserve_prices_msg); - assert_eq!( - response.unwrap_err().to_string(), - "InvalidInput: denom not found" - ); - - // Removing existent denoms is ok - let remove_coins = vec!["uosmo".to_string(), "ujuno".to_string()]; - let unset_min_reserve_prices_msg = SudoMsg::UnsetMinReservePrices { - denoms: remove_coins, - }; - let response = router.wasm_sudo(reserve_auction.clone(), &unset_min_reserve_prices_msg); - assert!(response.is_ok()); - - let next_coins_response: Vec = router - .wrap() - .query_wasm_smart( - reserve_auction, - &QueryMsg::MinReservePrices { - query_options: None, - }, - ) - .unwrap(); - - assert_eq!(next_coins_response.len(), coins_response.len()); -} From 6454b8ae1098c410be235bcfb283f4fc1e353764 Mon Sep 17 00:00:00 2001 From: Serkan Reis Date: Mon, 27 Jan 2025 12:35:20 +0300 Subject: [PATCH 2/4] Add min reserve price management logic --- Cargo.lock | 4 +- contracts/reserve-auction/src/error.rs | 3 + contracts/reserve-auction/src/execute.rs | 89 +++++++++++++++++++- contracts/reserve-auction/src/instantiate.rs | 8 +- contracts/reserve-auction/src/msg.rs | 12 +++ contracts/reserve-auction/src/query.rs | 12 ++- contracts/reserve-auction/src/state.rs | 1 + 7 files changed, 124 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19f65c90..dbd5f09f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1203,9 +1203,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] diff --git a/contracts/reserve-auction/src/error.rs b/contracts/reserve-auction/src/error.rs index f60b1235..dece3065 100644 --- a/contracts/reserve-auction/src/error.rs +++ b/contracts/reserve-auction/src/error.rs @@ -41,6 +41,9 @@ pub enum ContractError { #[error("InvalidReservePrice: {min}")] InvalidReservePrice { min: Coin }, + #[error("InvalidMinReservePriceManagerAddress")] + InvalidMinReservePriceManagerAddress {}, + #[error("BidTooLow: {0}")] BidTooLow(Uint128), diff --git a/contracts/reserve-auction/src/execute.rs b/contracts/reserve-auction/src/execute.rs index 42847097..62e387e9 100644 --- a/contracts/reserve-auction/src/execute.rs +++ b/contracts/reserve-auction/src/execute.rs @@ -3,7 +3,7 @@ use std::vec; use crate::error::ContractError; use crate::helpers::{only_no_auction, settle_auction, validate_reserve_price}; use crate::msg::ExecuteMsg; -use crate::state::{auctions, Auction, HighBid}; +use crate::state::{auctions, Auction, HighBid, MIN_RESERVE_PRICES, MIN_RESERVE_PRICE_MANAGER}; use crate::state::{CONFIG, HALT_MANAGER}; use cosmwasm_std::{ attr, coin, ensure, ensure_eq, has_coins, Addr, Coin, DepsMut, Env, Event, MessageInfo, @@ -76,6 +76,15 @@ pub fn execute( api.addr_validate(&collection)?, &token_id, ), + ExecuteMsg::SetMinReservePrices { min_reserve_prices } => { + execute_set_min_reserve_prices(deps, info, min_reserve_prices) + } + ExecuteMsg::UnsetMinReservePrices { denoms } => { + execute_unset_min_reserve_prices(deps, info, denoms) + } + ExecuteMsg::UpdateMinReservePriceManager { manager } => { + execute_update_min_reserve_price_manager(deps, info, manager) + } } } @@ -372,3 +381,81 @@ pub fn execute_settle_auction( settle_auction(deps, block_time, auction, &config, &halt_manager, response) } + +pub fn execute_set_min_reserve_prices( + deps: DepsMut, + info: MessageInfo, + min_reserve_prices: Vec, +) -> Result { + let min_reserve_price_manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; + ensure_eq!( + info.sender, + min_reserve_price_manager, + ContractError::Unauthorized {} + ); + + let mut response = Response::new(); + + for min_reserve_price in min_reserve_prices { + ensure!( + !MIN_RESERVE_PRICES.has(deps.storage, min_reserve_price.denom.clone()), + ContractError::InvalidInput("found duplicate denom".to_string()) + ); + + MIN_RESERVE_PRICES.save( + deps.storage, + min_reserve_price.denom.clone(), + &min_reserve_price.amount, + )?; + response = response.add_event( + Event::new("set-min-reserve-price") + .add_attribute("denom", min_reserve_price.denom) + .add_attribute("amount", min_reserve_price.amount), + ); + } + Ok(response) +} + +pub fn execute_unset_min_reserve_prices( + deps: DepsMut, + info: MessageInfo, + denoms: Vec, +) -> Result { + let min_reserve_price_manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; + ensure_eq!( + info.sender, + min_reserve_price_manager, + ContractError::Unauthorized {} + ); + + let mut response = Response::new(); + + for denom in denoms { + ensure!( + MIN_RESERVE_PRICES.has(deps.storage, denom.clone()), + ContractError::InvalidInput("denom not found".to_string()) + ); + + MIN_RESERVE_PRICES.remove(deps.storage, denom.clone()); + response = + response.add_event(Event::new("unset-min-reserve-price").add_attribute("denom", denom)); + } + Ok(response) +} + +pub fn execute_update_min_reserve_price_manager( + deps: DepsMut, + info: MessageInfo, + manager: String, +) -> Result { + let min_reserve_price_manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; + ensure_eq!( + info.sender, + min_reserve_price_manager, + ContractError::Unauthorized {} + ); + + MIN_RESERVE_PRICE_MANAGER.save(deps.storage, &deps.api.addr_validate(&manager)?)?; + + Ok(Response::new().add_attribute("action", "update-min-reserve-price-manager")) +} diff --git a/contracts/reserve-auction/src/instantiate.rs b/contracts/reserve-auction/src/instantiate.rs index 8d668b2c..5a56352c 100644 --- a/contracts/reserve-auction/src/instantiate.rs +++ b/contracts/reserve-auction/src/instantiate.rs @@ -2,7 +2,7 @@ use cosmwasm_std::entry_point; use crate::msg::InstantiateMsg; -use crate::state::{Config, HaltManager, HALT_MANAGER}; +use crate::state::{Config, HaltManager, HALT_MANAGER, MIN_RESERVE_PRICE_MANAGER}; use crate::{error::ContractError, state::MIN_RESERVE_PRICES}; use cosmwasm_std::{DepsMut, Env, Event, MessageInfo}; use cw2::set_contract_version; @@ -20,6 +20,12 @@ pub fn instantiate( msg: InstantiateMsg, ) -> Result { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + MIN_RESERVE_PRICE_MANAGER.save( + deps.storage, + &deps.api.addr_validate(&msg.min_reserve_price_manager)?, + )?; + let config = Config { fair_burn: deps.api.addr_validate(&msg.fair_burn)?, trading_fee_percent: msg.trading_fee_percent, diff --git a/contracts/reserve-auction/src/msg.rs b/contracts/reserve-auction/src/msg.rs index 6ad108ed..69155e2a 100644 --- a/contracts/reserve-auction/src/msg.rs +++ b/contracts/reserve-auction/src/msg.rs @@ -37,6 +37,7 @@ pub struct InstantiateMsg { /// The minimum reserve prices for the various denoms. Denoms /// no defined are not supported. pub min_reserve_prices: Vec, + pub min_reserve_price_manager: String, } #[cw_serde] @@ -65,6 +66,15 @@ pub enum ExecuteMsg { collection: String, token_id: String, }, + SetMinReservePrices { + min_reserve_prices: Vec, + }, + UnsetMinReservePrices { + denoms: Vec, + }, + UpdateMinReservePriceManager { + manager: String, + }, } #[cw_serde] @@ -106,6 +116,8 @@ pub enum QueryMsg { end_time: u64, query_options: Option>, }, + #[returns(String)] + MinReservePriceManager {}, } #[allow(clippy::large_enum_variant)] diff --git a/contracts/reserve-auction/src/query.rs b/contracts/reserve-auction/src/query.rs index 51842c97..1a45d007 100644 --- a/contracts/reserve-auction/src/query.rs +++ b/contracts/reserve-auction/src/query.rs @@ -1,5 +1,7 @@ use crate::msg::{AuctionKeyOffset, MinReservePriceOffset, QueryMsg}; -use crate::state::{auctions, Auction, Config, HaltManager, HALT_MANAGER}; +use crate::state::{ + auctions, Auction, Config, HaltManager, HALT_MANAGER, MIN_RESERVE_PRICE_MANAGER, +}; use crate::state::{CONFIG, MIN_RESERVE_PRICES}; use cosmwasm_std::{coin, to_json_binary, Addr, Binary, Coin, Deps, Env, StdResult}; @@ -42,6 +44,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { end_time, query_options.unwrap_or_default(), )?), + QueryMsg::MinReservePriceManager {} => { + to_json_binary(&query_min_reserve_price_manager(deps)?) + } } } @@ -75,6 +80,11 @@ pub fn query_min_reserve_prices( Ok(coins) } +pub fn query_min_reserve_price_manager(deps: Deps) -> StdResult { + let manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; + Ok(manager.to_string()) +} + pub fn query_auction( deps: Deps, collection: String, diff --git a/contracts/reserve-auction/src/state.rs b/contracts/reserve-auction/src/state.rs index 98862960..46391b34 100644 --- a/contracts/reserve-auction/src/state.rs +++ b/contracts/reserve-auction/src/state.rs @@ -58,6 +58,7 @@ pub const CONFIG: Item = Item::new("cfg"); // A map of acceptable denoms to their minimum reserve price. // Denoms not found in the Map are not accepted. pub const MIN_RESERVE_PRICES: Map = Map::new("mrp"); +pub const MIN_RESERVE_PRICE_MANAGER: Item = Item::new("mrpm"); #[cw_serde] pub struct HighBid { From 156149b77a862d5d384750b35f9a71a4113479f4 Mon Sep 17 00:00:00 2001 From: Serkan Reis Date: Mon, 27 Jan 2025 12:36:50 +0300 Subject: [PATCH 3/4] Add min reserve price management tests --- .../src/tests/setup/setup_auctions.rs | 2 + .../src/tests/unit_tests/alt_denom.rs | 192 +++++++++++++++++- .../src/tests/unit_tests/auction.rs | 2 + 3 files changed, 195 insertions(+), 1 deletion(-) diff --git a/contracts/reserve-auction/src/tests/setup/setup_auctions.rs b/contracts/reserve-auction/src/tests/setup/setup_auctions.rs index 963b4c85..318bac4c 100644 --- a/contracts/reserve-auction/src/tests/setup/setup_auctions.rs +++ b/contracts/reserve-auction/src/tests/setup/setup_auctions.rs @@ -16,6 +16,7 @@ use super::setup_contracts::*; pub const DUMMY_DENOM: &str = "ibc/773B5B5E24EC48005205A2EB35E6C0743EE47C9147E94BD5A4E0CBB63082314D"; +pub const DUMMY_MIN_RESERVE_PRICE_MANAGER: &str = "min-reserve-price-manager"; pub fn setup_reserve_auction( router: &mut StargazeApp, @@ -39,6 +40,7 @@ pub fn setup_reserve_auction( coin(MIN_RESERVE_PRICE, NATIVE_DENOM), coin(MIN_RESERVE_PRICE, DUMMY_DENOM), ], + min_reserve_price_manager: DUMMY_MIN_RESERVE_PRICE_MANAGER.to_string(), }; let auction = router .instantiate_contract( diff --git a/contracts/reserve-auction/src/tests/unit_tests/alt_denom.rs b/contracts/reserve-auction/src/tests/unit_tests/alt_denom.rs index ace81a90..1ce6765e 100644 --- a/contracts/reserve-auction/src/tests/unit_tests/alt_denom.rs +++ b/contracts/reserve-auction/src/tests/unit_tests/alt_denom.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use crate::msg::ExecuteMsg; +use crate::msg::{ExecuteMsg, QueryMsg}; use crate::tests::helpers::constants::{ CREATE_AUCTION_FEE, DEFAULT_DURATION, EXTEND_DURATION, MAX_DURATION, MIN_BID_INCREMENT_PCT, MIN_DURATION, MIN_RESERVE_PRICE, @@ -21,6 +21,7 @@ use crate::tests::{ }; use crate::ContractError; +use crate::tests::setup::setup_auctions::DUMMY_MIN_RESERVE_PRICE_MANAGER; use cosmwasm_std::{coin, Coin, Decimal, StdError, Uint128}; use cw_multi_test::Executor; use regex::Regex; @@ -905,3 +906,192 @@ fn try_settle_auction_with_no_bids() { let res = router.execute_contract(creator.clone(), auction.clone(), &msg, &[]); assert_error(res, ContractError::AuctionNotEnded {}.to_string()); } + +#[test] +fn try_update_min_reserve_prices() { + let vt = standard_minter_template(1); + let (mut router, creator, _bidder) = (vt.router, vt.accts.creator, vt.accts.bidder); + let fair_burn = setup_fair_burn(&mut router, creator.clone()); + let reserve_auction = setup_reserve_auction(&mut router, creator.clone(), fair_burn).unwrap(); + + setup_block_time(&mut router, GENESIS_MINT_START_TIME, None); + + let min_reserve_price_manager = setup_addtl_account( + &mut router, + DUMMY_MIN_RESERVE_PRICE_MANAGER, + INITIAL_BALANCE, + ) + .unwrap(); + + let wrong_min_reserve_price_manager = setup_addtl_account( + &mut router, + "false_min_reserve_price_manager", + INITIAL_BALANCE, + ) + .unwrap(); + + let coins_response: Vec = router + .wrap() + .query_wasm_smart( + reserve_auction.clone(), + &QueryMsg::MinReservePrices { + query_options: None, + }, + ) + .unwrap(); + + // Duplicate denom throws error + let set_min_reserve_prices_msg = ExecuteMsg::SetMinReservePrices { + min_reserve_prices: vec![coins_response[0].clone()], + }; + let response = router.execute_contract( + min_reserve_price_manager.clone(), + reserve_auction.clone(), + &set_min_reserve_prices_msg, + &[], + ); + assert_eq!( + response.unwrap_err().root_cause().to_string(), + "InvalidInput: found duplicate denom" + ); + + // New denoms can only be added by the manager + let new_coins = vec![coin(3000000, "uosmo"), coin(4000000, "ujuno")]; + let set_min_reserve_prices_msg = ExecuteMsg::SetMinReservePrices { + min_reserve_prices: new_coins.clone(), + }; + let response = router.execute_contract( + wrong_min_reserve_price_manager.clone(), + reserve_auction.clone(), + &set_min_reserve_prices_msg, + &[], + ); + assert_error(response, ContractError::Unauthorized {}.to_string()); + + let new_coins = vec![coin(3000000, "uosmo"), coin(4000000, "ujuno")]; + let set_min_reserve_prices_msg = ExecuteMsg::SetMinReservePrices { + min_reserve_prices: new_coins.clone(), + }; + let response = router.execute_contract( + min_reserve_price_manager.clone(), + reserve_auction.clone(), + &set_min_reserve_prices_msg, + &[], + ); + assert!(response.is_ok()); + + let next_coins_response: Vec = router + .wrap() + .query_wasm_smart( + reserve_auction.clone(), + &QueryMsg::MinReservePrices { + query_options: None, + }, + ) + .unwrap(); + + let mut expected_coins = coins_response.clone(); + expected_coins.extend(new_coins); + assert_eq!(next_coins_response.len(), expected_coins.len()); + + // Removing non-existent denoms throws error + let unset_min_reserve_prices_msg = ExecuteMsg::UnsetMinReservePrices { + denoms: vec!["uusd".to_string()], + }; + let response = router.execute_contract( + min_reserve_price_manager.clone(), + reserve_auction.clone(), + &unset_min_reserve_prices_msg, + &[], + ); + assert_eq!( + response.unwrap_err().root_cause().to_string(), + "InvalidInput: denom not found" + ); + + // Removing existent denoms can only be done by the manager + let remove_coins = vec!["uosmo".to_string(), "ujuno".to_string()]; + let unset_min_reserve_prices_msg = ExecuteMsg::UnsetMinReservePrices { + denoms: remove_coins, + }; + let response = router.execute_contract( + wrong_min_reserve_price_manager.clone(), + reserve_auction.clone(), + &unset_min_reserve_prices_msg, + &[], + ); + assert_error(response, ContractError::Unauthorized {}.to_string()); + + let response = router.execute_contract( + min_reserve_price_manager.clone(), + reserve_auction.clone(), + &unset_min_reserve_prices_msg, + &[], + ); + assert!(response.is_ok()); + + let next_coins_response: Vec = router + .wrap() + .query_wasm_smart( + reserve_auction, + &QueryMsg::MinReservePrices { + query_options: None, + }, + ) + .unwrap(); + + assert_eq!(next_coins_response.len(), coins_response.len()); +} + +#[test] +fn try_update_min_reserve_price_manager() { + let vt = standard_minter_template(1); + let (mut router, creator, _bidder) = (vt.router, vt.accts.creator, vt.accts.bidder); + let fair_burn = setup_fair_burn(&mut router, creator.clone()); + let reserve_auction = setup_reserve_auction(&mut router, creator.clone(), fair_burn).unwrap(); + + setup_block_time(&mut router, GENESIS_MINT_START_TIME, None); + + let min_reserve_price_manager = setup_addtl_account( + &mut router, + DUMMY_MIN_RESERVE_PRICE_MANAGER, + INITIAL_BALANCE, + ) + .unwrap(); + + let wrong_min_reserve_price_manager = setup_addtl_account( + &mut router, + "false_min_reserve_price_manager", + INITIAL_BALANCE, + ) + .unwrap(); + + let update_min_reserve_price_manager_msg = ExecuteMsg::UpdateMinReservePriceManager { + manager: "new_manager".to_string(), + }; + + let response = router.execute_contract( + wrong_min_reserve_price_manager.clone(), + reserve_auction.clone(), + &update_min_reserve_price_manager_msg, + &[], + ); + assert_error(response, ContractError::Unauthorized {}.to_string()); + + let response = router.execute_contract( + min_reserve_price_manager.clone(), + reserve_auction.clone(), + &update_min_reserve_price_manager_msg, + &[], + ); + assert!(response.is_ok()); + + let new_manager: String = router + .wrap() + .query_wasm_smart( + reserve_auction.clone(), + &QueryMsg::MinReservePriceManager {}, + ) + .unwrap(); + assert_eq!(new_manager, "new_manager".to_string()); +} diff --git a/contracts/reserve-auction/src/tests/unit_tests/auction.rs b/contracts/reserve-auction/src/tests/unit_tests/auction.rs index 2edb2a13..acf78cc1 100644 --- a/contracts/reserve-auction/src/tests/unit_tests/auction.rs +++ b/contracts/reserve-auction/src/tests/unit_tests/auction.rs @@ -23,6 +23,7 @@ use crate::tests::{ }; use crate::ContractError; +use crate::tests::setup::setup_auctions::DUMMY_MIN_RESERVE_PRICE_MANAGER; use cosmwasm_std::{coin, Addr, Decimal, StdError, Uint128}; use cw_multi_test::Executor; use sg721_base::msg::{CollectionInfoResponse, QueryMsg as Sg721QueryMsg}; @@ -51,6 +52,7 @@ fn try_instantiate() { halt_buffer_duration: HALT_BUFFER_DURATION, halt_postpone_duration: HALT_POSTPONE_DURATION, min_reserve_prices: vec![coin(MIN_RESERVE_PRICE, NATIVE_DENOM)], + min_reserve_price_manager: DUMMY_MIN_RESERVE_PRICE_MANAGER.to_string(), }; let auction_addr = instantiate_auction(&mut app, auction_id, msg.clone()); From 3d9c75667db2ea236bd3d575412f2d989f5d5180 Mon Sep 17 00:00:00 2001 From: Serkan Reis Date: Mon, 17 Feb 2025 21:29:39 +0300 Subject: [PATCH 4/4] Replace duplicate code with helper fn --- contracts/reserve-auction/src/execute.rs | 25 ++++++------------------ contracts/reserve-auction/src/helpers.rs | 16 +++++++++++++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/contracts/reserve-auction/src/execute.rs b/contracts/reserve-auction/src/execute.rs index 62e387e9..adf190d7 100644 --- a/contracts/reserve-auction/src/execute.rs +++ b/contracts/reserve-auction/src/execute.rs @@ -1,7 +1,9 @@ use std::vec; use crate::error::ContractError; -use crate::helpers::{only_no_auction, settle_auction, validate_reserve_price}; +use crate::helpers::{ + only_min_reserve_price_manager, only_no_auction, settle_auction, validate_reserve_price, +}; use crate::msg::ExecuteMsg; use crate::state::{auctions, Auction, HighBid, MIN_RESERVE_PRICES, MIN_RESERVE_PRICE_MANAGER}; use crate::state::{CONFIG, HALT_MANAGER}; @@ -387,12 +389,7 @@ pub fn execute_set_min_reserve_prices( info: MessageInfo, min_reserve_prices: Vec, ) -> Result { - let min_reserve_price_manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; - ensure_eq!( - info.sender, - min_reserve_price_manager, - ContractError::Unauthorized {} - ); + only_min_reserve_price_manager(deps.as_ref(), &info.sender)?; let mut response = Response::new(); @@ -421,12 +418,7 @@ pub fn execute_unset_min_reserve_prices( info: MessageInfo, denoms: Vec, ) -> Result { - let min_reserve_price_manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; - ensure_eq!( - info.sender, - min_reserve_price_manager, - ContractError::Unauthorized {} - ); + only_min_reserve_price_manager(deps.as_ref(), &info.sender)?; let mut response = Response::new(); @@ -448,12 +440,7 @@ pub fn execute_update_min_reserve_price_manager( info: MessageInfo, manager: String, ) -> Result { - let min_reserve_price_manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; - ensure_eq!( - info.sender, - min_reserve_price_manager, - ContractError::Unauthorized {} - ); + only_min_reserve_price_manager(deps.as_ref(), &info.sender)?; MIN_RESERVE_PRICE_MANAGER.save(deps.storage, &deps.api.addr_validate(&manager)?)?; diff --git a/contracts/reserve-auction/src/helpers.rs b/contracts/reserve-auction/src/helpers.rs index 122dbcd3..932fccb7 100644 --- a/contracts/reserve-auction/src/helpers.rs +++ b/contracts/reserve-auction/src/helpers.rs @@ -1,11 +1,13 @@ -use cosmwasm_std::{coin, ensure, Addr, Coin, Deps, DepsMut, Event, Storage, Timestamp}; +use cosmwasm_std::{coin, ensure, ensure_eq, Addr, Coin, Deps, DepsMut, Event, Storage, Timestamp}; use sg_marketplace_common::{ nft::{load_collection_royalties, transfer_nft}, sale::payout_nft_sale_fees, }; use sg_std::Response; -use crate::state::{auctions, Auction, Config, HaltManager, MIN_RESERVE_PRICES}; +use crate::state::{ + auctions, Auction, Config, HaltManager, MIN_RESERVE_PRICES, MIN_RESERVE_PRICE_MANAGER, +}; use crate::ContractError; pub fn only_no_auction(deps: Deps, collection: &Addr, token_id: &str) -> Result<(), ContractError> { @@ -21,6 +23,16 @@ pub fn only_no_auction(deps: Deps, collection: &Addr, token_id: &str) -> Result< Ok(()) } +pub fn only_min_reserve_price_manager(deps: Deps, sender: &Addr) -> Result<(), ContractError> { + let min_reserve_price_manager = MIN_RESERVE_PRICE_MANAGER.load(deps.storage)?; + ensure_eq!( + sender, + min_reserve_price_manager, + ContractError::Unauthorized {} + ); + Ok(()) +} + pub fn validate_reserve_price( storage: &dyn Storage, check_reserve_price: &Coin,