|
1 | 1 | use std::vec; |
2 | 2 |
|
3 | 3 | use crate::error::ContractError; |
4 | | -use crate::helpers::{only_no_auction, settle_auction, validate_reserve_price}; |
| 4 | +use crate::helpers::{ |
| 5 | + build_blacklist_key, only_blacklist_manager, only_min_reserve_price_manager, only_no_auction, |
| 6 | + only_not_blacklisted, settle_auction, validate_reserve_price, BLACKLIST_MANAGER, |
| 7 | +}; |
5 | 8 | use crate::msg::ExecuteMsg; |
6 | | -use crate::state::{auctions, Auction, HighBid}; |
7 | | -use crate::state::{CONFIG, HALT_MANAGER}; |
| 9 | +use crate::state::{ |
| 10 | + auctions, Auction, HighBid, BLACKLIST, CONFIG, HALT_MANAGER, MIN_RESERVE_PRICES, |
| 11 | + MIN_RESERVE_PRICE_MANAGER, |
| 12 | +}; |
8 | 13 | use cosmwasm_std::{ |
9 | 14 | attr, coin, ensure, ensure_eq, has_coins, Addr, Coin, DepsMut, Env, Event, MessageInfo, |
10 | 15 | Timestamp, |
@@ -76,6 +81,36 @@ pub fn execute( |
76 | 81 | api.addr_validate(&collection)?, |
77 | 82 | &token_id, |
78 | 83 | ), |
| 84 | + ExecuteMsg::SetMinReservePrices { min_reserve_prices } => { |
| 85 | + execute_set_min_reserve_prices(deps, info, min_reserve_prices) |
| 86 | + } |
| 87 | + ExecuteMsg::UnsetMinReservePrices { denoms } => { |
| 88 | + execute_unset_min_reserve_prices(deps, info, denoms) |
| 89 | + } |
| 90 | + ExecuteMsg::UpdateMinReservePriceManager { manager } => { |
| 91 | + execute_update_min_reserve_price_manager(deps, info, manager) |
| 92 | + } |
| 93 | + ExecuteMsg::AddToBlacklist { |
| 94 | + collection, |
| 95 | + token_id, |
| 96 | + } => execute_add_to_blacklist(deps, info, api.addr_validate(&collection)?, token_id), |
| 97 | + ExecuteMsg::RemoveFromBlacklist { |
| 98 | + collection, |
| 99 | + token_id, |
| 100 | + } => execute_remove_from_blacklist(deps, info, api.addr_validate(&collection)?, token_id), |
| 101 | + ExecuteMsg::BatchAddToBlacklist { |
| 102 | + collection, |
| 103 | + token_ids, |
| 104 | + } => execute_batch_add_to_blacklist(deps, info, api.addr_validate(&collection)?, token_ids), |
| 105 | + ExecuteMsg::BatchRemoveFromBlacklist { |
| 106 | + collection, |
| 107 | + token_ids, |
| 108 | + } => execute_batch_remove_from_blacklist( |
| 109 | + deps, |
| 110 | + info, |
| 111 | + api.addr_validate(&collection)?, |
| 112 | + token_ids, |
| 113 | + ), |
79 | 114 | } |
80 | 115 | } |
81 | 116 |
|
@@ -109,6 +144,9 @@ pub fn execute_create_auction( |
109 | 144 |
|
110 | 145 | only_tradable(&deps.querier, &env.block, &collection)?; |
111 | 146 |
|
| 147 | + // Check if token is blacklisted |
| 148 | + only_not_blacklisted(deps.as_ref().storage, &collection, token_id)?; |
| 149 | + |
112 | 150 | let mut response = Response::new(); |
113 | 151 |
|
114 | 152 | validate_reserve_price(deps.as_ref().storage, &reserve_price)?; |
@@ -230,8 +268,12 @@ pub fn execute_cancel_auction( |
230 | 268 | nonpayable(&info)?; |
231 | 269 | let auction = auctions().load(deps.storage, (collection.clone(), token_id.to_string()))?; |
232 | 270 |
|
233 | | - // Ensure caller is the seller |
234 | | - ensure_eq!(auction.seller, info.sender, ContractError::Unauthorized {}); |
| 271 | + let is_blacklist_manager = info.sender.as_str() == BLACKLIST_MANAGER; |
| 272 | + |
| 273 | + if !is_blacklist_manager { |
| 274 | + // Ensure caller is the seller |
| 275 | + ensure_eq!(auction.seller, info.sender, ContractError::Unauthorized {}); |
| 276 | + } |
235 | 277 |
|
236 | 278 | // Ensure auction hasn't started |
237 | 279 | ensure!( |
@@ -267,6 +309,9 @@ pub fn execute_place_bid( |
267 | 309 |
|
268 | 310 | let mut auction = auctions().load(deps.storage, (collection, token_id.to_string()))?; |
269 | 311 |
|
| 312 | + // Check if token is blacklisted |
| 313 | + only_not_blacklisted(deps.as_ref().storage, &auction.collection, token_id)?; |
| 314 | + |
270 | 315 | let auction_denom = auction.denom(); |
271 | 316 | let bid_amount = must_pay(&info, &auction_denom)?; |
272 | 317 |
|
@@ -372,3 +417,146 @@ pub fn execute_settle_auction( |
372 | 417 |
|
373 | 418 | settle_auction(deps, block_time, auction, &config, &halt_manager, response) |
374 | 419 | } |
| 420 | + |
| 421 | +pub fn execute_set_min_reserve_prices( |
| 422 | + deps: DepsMut, |
| 423 | + info: MessageInfo, |
| 424 | + min_reserve_prices: Vec<Coin>, |
| 425 | +) -> Result<Response, ContractError> { |
| 426 | + only_min_reserve_price_manager(deps.as_ref(), &info.sender)?; |
| 427 | + |
| 428 | + let mut response = Response::new(); |
| 429 | + |
| 430 | + for min_reserve_price in min_reserve_prices { |
| 431 | + ensure!( |
| 432 | + !MIN_RESERVE_PRICES.has(deps.storage, min_reserve_price.denom.clone()), |
| 433 | + ContractError::InvalidInput("found duplicate denom".to_string()) |
| 434 | + ); |
| 435 | + |
| 436 | + MIN_RESERVE_PRICES.save( |
| 437 | + deps.storage, |
| 438 | + min_reserve_price.denom.clone(), |
| 439 | + &min_reserve_price.amount, |
| 440 | + )?; |
| 441 | + response = response.add_event( |
| 442 | + Event::new("set-min-reserve-price") |
| 443 | + .add_attribute("denom", min_reserve_price.denom) |
| 444 | + .add_attribute("amount", min_reserve_price.amount), |
| 445 | + ); |
| 446 | + } |
| 447 | + Ok(response) |
| 448 | +} |
| 449 | + |
| 450 | +pub fn execute_unset_min_reserve_prices( |
| 451 | + deps: DepsMut, |
| 452 | + info: MessageInfo, |
| 453 | + denoms: Vec<String>, |
| 454 | +) -> Result<Response, ContractError> { |
| 455 | + only_min_reserve_price_manager(deps.as_ref(), &info.sender)?; |
| 456 | + |
| 457 | + let mut response = Response::new(); |
| 458 | + |
| 459 | + for denom in denoms { |
| 460 | + ensure!( |
| 461 | + MIN_RESERVE_PRICES.has(deps.storage, denom.clone()), |
| 462 | + ContractError::InvalidInput("denom not found".to_string()) |
| 463 | + ); |
| 464 | + |
| 465 | + MIN_RESERVE_PRICES.remove(deps.storage, denom.clone()); |
| 466 | + response = |
| 467 | + response.add_event(Event::new("unset-min-reserve-price").add_attribute("denom", denom)); |
| 468 | + } |
| 469 | + Ok(response) |
| 470 | +} |
| 471 | + |
| 472 | +pub fn execute_update_min_reserve_price_manager( |
| 473 | + deps: DepsMut, |
| 474 | + info: MessageInfo, |
| 475 | + manager: String, |
| 476 | +) -> Result<Response, ContractError> { |
| 477 | + only_min_reserve_price_manager(deps.as_ref(), &info.sender)?; |
| 478 | + |
| 479 | + MIN_RESERVE_PRICE_MANAGER.save(deps.storage, &deps.api.addr_validate(&manager)?)?; |
| 480 | + |
| 481 | + Ok(Response::new().add_attribute("action", "update-min-reserve-price-manager")) |
| 482 | +} |
| 483 | + |
| 484 | +pub fn execute_add_to_blacklist( |
| 485 | + deps: DepsMut, |
| 486 | + info: MessageInfo, |
| 487 | + collection: Addr, |
| 488 | + token_id: String, |
| 489 | +) -> Result<Response, ContractError> { |
| 490 | + only_blacklist_manager(&info.sender)?; |
| 491 | + |
| 492 | + let key = build_blacklist_key(collection.as_ref(), &token_id); |
| 493 | + BLACKLIST.save(deps.storage, key, &())?; |
| 494 | + |
| 495 | + let response = Response::new() |
| 496 | + .add_attribute("action", "add-to-blacklist") |
| 497 | + .add_attribute("collection", collection.to_string()) |
| 498 | + .add_attribute("token_id", token_id); |
| 499 | + |
| 500 | + Ok(response) |
| 501 | +} |
| 502 | + |
| 503 | +pub fn execute_remove_from_blacklist( |
| 504 | + deps: DepsMut, |
| 505 | + info: MessageInfo, |
| 506 | + collection: Addr, |
| 507 | + token_id: String, |
| 508 | +) -> Result<Response, ContractError> { |
| 509 | + only_blacklist_manager(&info.sender)?; |
| 510 | + |
| 511 | + let key = build_blacklist_key(collection.as_ref(), &token_id); |
| 512 | + BLACKLIST.remove(deps.storage, key); |
| 513 | + |
| 514 | + let response = Response::new() |
| 515 | + .add_attribute("action", "remove-from-blacklist") |
| 516 | + .add_attribute("collection", collection.to_string()) |
| 517 | + .add_attribute("token_id", token_id); |
| 518 | + |
| 519 | + Ok(response) |
| 520 | +} |
| 521 | + |
| 522 | +pub fn execute_batch_add_to_blacklist( |
| 523 | + deps: DepsMut, |
| 524 | + info: MessageInfo, |
| 525 | + collection: Addr, |
| 526 | + token_ids: Vec<String>, |
| 527 | +) -> Result<Response, ContractError> { |
| 528 | + only_blacklist_manager(&info.sender)?; |
| 529 | + |
| 530 | + for token_id in &token_ids { |
| 531 | + let key = build_blacklist_key(collection.as_ref(), token_id); |
| 532 | + BLACKLIST.save(deps.storage, key, &())?; |
| 533 | + } |
| 534 | + |
| 535 | + let response = Response::new() |
| 536 | + .add_attribute("action", "batch-add-to-blacklist") |
| 537 | + .add_attribute("collection", collection.to_string()) |
| 538 | + .add_attribute("count", token_ids.len().to_string()); |
| 539 | + |
| 540 | + Ok(response) |
| 541 | +} |
| 542 | + |
| 543 | +pub fn execute_batch_remove_from_blacklist( |
| 544 | + deps: DepsMut, |
| 545 | + info: MessageInfo, |
| 546 | + collection: Addr, |
| 547 | + token_ids: Vec<String>, |
| 548 | +) -> Result<Response, ContractError> { |
| 549 | + only_blacklist_manager(&info.sender)?; |
| 550 | + |
| 551 | + for token_id in &token_ids { |
| 552 | + let key = build_blacklist_key(collection.as_ref(), token_id); |
| 553 | + BLACKLIST.remove(deps.storage, key); |
| 554 | + } |
| 555 | + |
| 556 | + let response = Response::new() |
| 557 | + .add_attribute("action", "batch-remove-from-blacklist") |
| 558 | + .add_attribute("collection", collection.to_string()) |
| 559 | + .add_attribute("count", token_ids.len().to_string()); |
| 560 | + |
| 561 | + Ok(response) |
| 562 | +} |
0 commit comments