Skip to content

Commit 823518c

Browse files
committed
allow reclaiming expired pending sales and disallow manager to still approve them
1 parent e3dadc6 commit 823518c

File tree

5 files changed

+561
-8
lines changed

5 files changed

+561
-8
lines changed

contracts/marketplace/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,10 @@ pub enum ContractError {
6363
collection: String,
6464
token_id: String,
6565
},
66+
67+
#[error("Pending sale expired: {id}")]
68+
PendingSaleExpired { id: String },
69+
70+
#[error("Pending sale not yet expired: {id}")]
71+
PendingSaleNotExpired { id: String },
6672
}

contracts/marketplace/src/events.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub fn sale_rejected_event(
155155
buyer: Addr,
156156
seller: Addr,
157157
price: Coin,
158+
reason: &str,
158159
) -> Event {
159160
Event::new(format!("{}/sale-rejected", env!("CARGO_PKG_NAME")))
160161
.add_attribute("pending_sale_id", pending_sale_id)
@@ -163,4 +164,5 @@ pub fn sale_rejected_event(
163164
.add_attribute("buyer", buyer.to_string())
164165
.add_attribute("seller", seller.to_string())
165166
.add_attribute("price", price.to_string())
167+
.add_attribute("reason", reason)
166168
}

contracts/marketplace/src/execute.rs

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ pub fn execute(
105105
),
106106

107107
ExecuteMsg::CancelCollectionOffer { id } => execute_cancel_collection_offer(deps, info, id),
108-
ExecuteMsg::ApproveSale { id } => execute_approve_sale(deps, info, id),
108+
ExecuteMsg::ApproveSale { id } => execute_approve_sale(deps, env, info, id),
109109
ExecuteMsg::RejectSale { id } => execute_reject_sale(deps, info, id),
110+
ExecuteMsg::ReclaimExpiredSale { id } => execute_reclaim_expired_sale(deps, env, info, id),
110111
ExecuteMsg::UpdateConfig { config } => execute_update_config(deps, info, config),
111112
}
112113
}
@@ -400,6 +401,7 @@ fn execute_create_pending_sale(
400401

401402
pub fn execute_approve_sale(
402403
deps: DepsMut,
404+
env: Env,
403405
info: MessageInfo,
404406
pending_sale_id: String,
405407
) -> Result<Response, ContractError> {
@@ -409,6 +411,12 @@ pub fn execute_approve_sale(
409411
let config = CONFIG.load(deps.storage)?;
410412
let pending_sale = pending_sales().load(deps.storage, pending_sale_id.clone())?;
411413

414+
if env.block.time.seconds() >= pending_sale.expiration {
415+
return Err(ContractError::PendingSaleExpired {
416+
id: pending_sale_id,
417+
});
418+
}
419+
412420
// Generate listing_id to find the listing
413421
let listing_id = generate_id(vec![
414422
pending_sale.collection.as_bytes(),
@@ -478,16 +486,12 @@ pub fn execute_approve_sale(
478486
Ok(response)
479487
}
480488

481-
pub fn execute_reject_sale(
489+
fn remove_pending_sale(
482490
deps: DepsMut,
483-
info: MessageInfo,
484491
pending_sale_id: String,
492+
pending_sale: PendingSale,
493+
reason: &str,
485494
) -> Result<Response, ContractError> {
486-
// Only manager can reject
487-
only_manager(&info, &deps)?;
488-
489-
let pending_sale = pending_sales().load(deps.storage, pending_sale_id.clone())?;
490-
491495
let listing_id = generate_id(vec![
492496
pending_sale.collection.as_bytes(),
493497
pending_sale.token_id.as_bytes(),
@@ -514,6 +518,7 @@ pub fn execute_reject_sale(
514518
funds: vec![],
515519
});
516520
}
521+
517522
// refund buyer
518523
let refund_msg = BankMsg::Send {
519524
to_address: pending_sale.buyer.to_string(),
@@ -531,7 +536,43 @@ pub fn execute_reject_sale(
531536
pending_sale.buyer.clone(),
532537
pending_sale.seller,
533538
pending_sale.price,
539+
reason,
534540
))
535541
.add_message(refund_msg)
536542
.add_messages(sub_msgs))
537543
}
544+
545+
pub fn execute_reject_sale(
546+
deps: DepsMut,
547+
info: MessageInfo,
548+
pending_sale_id: String,
549+
) -> Result<Response, ContractError> {
550+
only_manager(&info, &deps)?;
551+
552+
let pending_sale = pending_sales().load(deps.storage, pending_sale_id.clone())?;
553+
554+
remove_pending_sale(deps, pending_sale_id, pending_sale, "rejected_by_manager")
555+
}
556+
557+
pub fn execute_reclaim_expired_sale(
558+
deps: DepsMut,
559+
env: Env,
560+
info: MessageInfo,
561+
pending_sale_id: String,
562+
) -> Result<Response, ContractError> {
563+
let pending_sale = pending_sales().load(deps.storage, pending_sale_id.clone())?;
564+
565+
if env.block.time.seconds() < pending_sale.expiration {
566+
return Err(ContractError::PendingSaleNotExpired {
567+
id: pending_sale_id,
568+
});
569+
}
570+
571+
if info.sender != pending_sale.buyer {
572+
return Err(ContractError::Unauthorized {
573+
message: "only the buyer can reclaim an expired sale".to_string(),
574+
});
575+
}
576+
577+
remove_pending_sale(deps, pending_sale_id, pending_sale, "expired")
578+
}

contracts/marketplace/src/msg.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ pub enum ExecuteMsg {
6060
RejectSale {
6161
id: String,
6262
},
63+
ReclaimExpiredSale {
64+
id: String,
65+
},
6366
UpdateConfig {
6467
config: Config<String>,
6568
},

0 commit comments

Comments
 (0)