Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8b56fcb

Browse files
authoredFeb 6, 2025··
Merge pull request #709 from public-awesome/serkan/wl-stage-mint-count-limit
Add optional mint count limit for tiered whitelist stages
2 parents fb34eaa + 5463638 commit 8b56fcb

File tree

39 files changed

+680
-81
lines changed

39 files changed

+680
-81
lines changed
 

‎contracts/minters/open-edition-minter-merkle-wl/src/contract.rs

+48-8
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use crate::msg::{
66
};
77
use crate::state::{
88
increment_token_index, Config, ConfigExtension, CONFIG, MINTABLE_NUM_TOKENS, MINTER_ADDRS,
9-
SG721_ADDRESS, STATUS, TOTAL_MINT_COUNT, WHITELIST_FS_MINTER_ADDRS, WHITELIST_MINTER_ADDRS,
10-
WHITELIST_SS_MINTER_ADDRS, WHITELIST_TS_MINTER_ADDRS,
9+
SG721_ADDRESS, STATUS, TOTAL_MINT_COUNT, WHITELIST_FS_MINTER_ADDRS, WHITELIST_FS_MINT_COUNT,
10+
WHITELIST_MINTER_ADDRS, WHITELIST_SS_MINTER_ADDRS, WHITELIST_SS_MINT_COUNT,
11+
WHITELIST_TS_MINTER_ADDRS, WHITELIST_TS_MINT_COUNT,
1112
};
1213
#[cfg(not(feature = "library"))]
1314
use cosmwasm_std::entry_point;
@@ -26,7 +27,7 @@ use sg2::query::Sg2QueryMsg;
2627
use sg4::{MinterConfig, Status, StatusResponse, SudoMsg};
2728
use sg721::{ExecuteMsg as Sg721ExecuteMsg, InstantiateMsg as Sg721InstantiateMsg};
2829
use sg_std::StargazeMsgWrapper;
29-
use tiered_whitelist_merkletree::msg::QueryMsg as TieredWhitelistQueryMsg;
30+
use tiered_whitelist_merkletree::msg::{QueryMsg as TieredWhitelistQueryMsg, StageResponse};
3031
use url::Url;
3132
use whitelist_mtree::msg::{
3233
ConfigResponse as WhitelistConfigResponse, HasMemberResponse, QueryMsg as WhitelistQueryMsg,
@@ -436,15 +437,36 @@ fn is_public_mint(
436437
}
437438

438439
// Check wl per address limit
439-
let wl_mint_count = whitelist_mint_count(deps, info, whitelist.clone())?.0;
440+
let wl_mint_count = whitelist_mint_count(deps, info, whitelist.clone())?;
440441
let max_count = match allocation {
441442
Some(allocation) => allocation,
442443
None => wl_config.per_address_limit,
443444
};
444-
if wl_mint_count >= max_count {
445+
if wl_mint_count.0 >= max_count {
445446
return Err(ContractError::MaxPerAddressLimitExceeded {});
446447
}
447448

449+
// Check if whitelist stage mint count limit is reached
450+
if wl_mint_count.1 && wl_mint_count.2.is_some() {
451+
let active_stage: StageResponse = deps.querier.query_wasm_smart(
452+
whitelist.clone(),
453+
&TieredWhitelistQueryMsg::Stage {
454+
stage_id: wl_mint_count.2.unwrap() - 1,
455+
},
456+
)?;
457+
if active_stage.stage.mint_count_limit.is_some() {
458+
let stage_mint_count = match wl_mint_count.2.unwrap() {
459+
1 => WHITELIST_FS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
460+
2 => WHITELIST_SS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
461+
3 => WHITELIST_TS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
462+
_ => return Err(ContractError::InvalidStageID {}),
463+
};
464+
if stage_mint_count >= active_stage.stage.mint_count_limit.unwrap() {
465+
return Err(ContractError::WhitelistMintCountLimitReached {});
466+
}
467+
}
468+
}
469+
448470
Ok(false)
449471
}
450472

@@ -1004,9 +1026,27 @@ fn save_whitelist_mint_count(
10041026
) -> StdResult<()> {
10051027
if is_tiered_whitelist & stage_id.is_some() {
10061028
match stage_id {
1007-
Some(1) => WHITELIST_FS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
1008-
Some(2) => WHITELIST_SS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
1009-
Some(3) => WHITELIST_TS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
1029+
Some(1) => {
1030+
let _ = WHITELIST_FS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
1031+
let mut wl_fs_mint_count =
1032+
WHITELIST_FS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
1033+
wl_fs_mint_count += 1;
1034+
WHITELIST_FS_MINT_COUNT.save(deps.storage, &wl_fs_mint_count)
1035+
}
1036+
Some(2) => {
1037+
let _ = WHITELIST_SS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
1038+
let mut wl_ss_mint_count =
1039+
WHITELIST_SS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
1040+
wl_ss_mint_count += 1;
1041+
WHITELIST_SS_MINT_COUNT.save(deps.storage, &wl_ss_mint_count)
1042+
}
1043+
Some(3) => {
1044+
let _ = WHITELIST_TS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
1045+
let mut wl_ts_mint_count =
1046+
WHITELIST_TS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
1047+
wl_ts_mint_count += 1;
1048+
WHITELIST_TS_MINT_COUNT.save(deps.storage, &wl_ts_mint_count)
1049+
}
10101050
_ => Err(StdError::generic_err("Invalid stage ID")),
10111051
}
10121052
} else {

‎contracts/minters/open-edition-minter-merkle-wl/src/error.rs

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ pub enum ContractError {
3131
#[error("Invalid reply ID")]
3232
InvalidReplyID {},
3333

34+
#[error("Invalid stage ID")]
35+
InvalidStageID {},
36+
3437
#[error("Not enough funds sent")]
3538
NotEnoughFunds {},
3639

@@ -121,6 +124,9 @@ pub enum ContractError {
121124
#[error("Max minting limit per address exceeded")]
122125
MaxPerAddressLimitExceeded {},
123126

127+
#[error("WhitelistMintCountLimitReached")]
128+
WhitelistMintCountLimitReached {},
129+
124130
#[error("Token id: {token_id} already sold")]
125131
TokenIdAlreadySold { token_id: u32 },
126132

‎contracts/minters/open-edition-minter-merkle-wl/src/state.rs

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub const WHITELIST_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlma");
2727
pub const WHITELIST_FS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlfsma");
2828
pub const WHITELIST_SS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlssma");
2929
pub const WHITELIST_TS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wltsma");
30+
pub const WHITELIST_FS_MINT_COUNT: Item<u32> = Item::new("wlfsmc");
31+
pub const WHITELIST_SS_MINT_COUNT: Item<u32> = Item::new("wlssmc");
32+
pub const WHITELIST_TS_MINT_COUNT: Item<u32> = Item::new("wltsmc");
3033
/// This keeps track of the mint count
3134
pub const TOTAL_MINT_COUNT: Item<u32> = Item::new("total_mint_count");
3235

‎contracts/minters/open-edition-minter-wl-flex/src/contract.rs

+50-10
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use crate::msg::{
66
};
77
use crate::state::{
88
increment_token_index, Config, ConfigExtension, CONFIG, MINTABLE_NUM_TOKENS, MINTER_ADDRS,
9-
SG721_ADDRESS, STATUS, TOTAL_MINT_COUNT, WHITELIST_FS_MINTER_ADDRS, WHITELIST_MINTER_ADDRS,
10-
WHITELIST_SS_MINTER_ADDRS, WHITELIST_TS_MINTER_ADDRS,
9+
SG721_ADDRESS, STATUS, TOTAL_MINT_COUNT, WHITELIST_FS_MINTER_ADDRS, WHITELIST_FS_MINT_COUNT,
10+
WHITELIST_MINTER_ADDRS, WHITELIST_SS_MINTER_ADDRS, WHITELIST_SS_MINT_COUNT,
11+
WHITELIST_TS_MINTER_ADDRS, WHITELIST_TS_MINT_COUNT,
1112
};
1213
#[cfg(not(feature = "library"))]
1314
use cosmwasm_std::entry_point;
@@ -26,7 +27,7 @@ use sg2::query::Sg2QueryMsg;
2627
use sg4::{MinterConfig, Status, StatusResponse, SudoMsg};
2728
use sg721::{ExecuteMsg as Sg721ExecuteMsg, InstantiateMsg as Sg721InstantiateMsg};
2829
use sg_std::StargazeMsgWrapper;
29-
use sg_tiered_whitelist_flex::msg::QueryMsg as TieredWhitelistQueryMsg;
30+
use sg_tiered_whitelist_flex::msg::{QueryMsg as TieredWhitelistQueryMsg, StageResponse};
3031
use sg_whitelist_flex::msg::{
3132
ConfigResponse as WhitelistConfigResponse, HasMemberResponse, Member,
3233
QueryMsg as WhitelistQueryMsg,
@@ -416,24 +417,45 @@ fn is_public_mint(deps: Deps, info: &MessageInfo) -> Result<bool, ContractError>
416417
}
417418

418419
// Check wl per address limit
419-
let wl_mint_count = whitelist_mint_count(deps, info, whitelist.clone())?.0;
420+
let wl_mint_count = whitelist_mint_count(deps, info, whitelist.clone())?;
420421
if config.extension.num_tokens.is_none() {
421422
ensure!(
422-
wl_mint_count < config.extension.per_address_limit,
423+
wl_mint_count.0 < config.extension.per_address_limit,
423424
ContractError::MaxPerAddressLimitExceeded {}
424425
);
425426
}
426427

427428
let wl_limit: Member = deps.querier.query_wasm_smart(
428-
whitelist,
429+
whitelist.clone(),
429430
&WhitelistQueryMsg::Member {
430431
member: info.sender.to_string(),
431432
},
432433
)?;
433-
if wl_mint_count >= wl_limit.mint_count {
434+
if wl_mint_count.0 >= wl_limit.mint_count {
434435
return Err(ContractError::MaxPerAddressLimitExceeded {});
435436
}
436437

438+
// Check if whitelist stage mint count limit is reached
439+
if wl_mint_count.1 && wl_mint_count.2.is_some() {
440+
let active_stage: StageResponse = deps.querier.query_wasm_smart(
441+
whitelist.clone(),
442+
&TieredWhitelistQueryMsg::Stage {
443+
stage_id: wl_mint_count.2.unwrap() - 1,
444+
},
445+
)?;
446+
if active_stage.stage.mint_count_limit.is_some() {
447+
let stage_mint_count = match wl_mint_count.2.unwrap() {
448+
1 => WHITELIST_FS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
449+
2 => WHITELIST_SS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
450+
3 => WHITELIST_TS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
451+
_ => return Err(ContractError::InvalidStageID {}),
452+
};
453+
if stage_mint_count >= active_stage.stage.mint_count_limit.unwrap() {
454+
return Err(ContractError::WhitelistMintCountLimitReached {});
455+
}
456+
}
457+
}
458+
437459
Ok(false)
438460
}
439461

@@ -504,9 +526,27 @@ fn save_whitelist_mint_count(
504526
) -> StdResult<()> {
505527
if is_tiered_whitelist & stage_id.is_some() {
506528
match stage_id {
507-
Some(1) => WHITELIST_FS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
508-
Some(2) => WHITELIST_SS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
509-
Some(3) => WHITELIST_TS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
529+
Some(1) => {
530+
let _ = WHITELIST_FS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
531+
let mut wl_fs_mint_count =
532+
WHITELIST_FS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
533+
wl_fs_mint_count += 1;
534+
WHITELIST_FS_MINT_COUNT.save(deps.storage, &wl_fs_mint_count)
535+
}
536+
Some(2) => {
537+
let _ = WHITELIST_SS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
538+
let mut wl_ss_mint_count =
539+
WHITELIST_SS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
540+
wl_ss_mint_count += 1;
541+
WHITELIST_SS_MINT_COUNT.save(deps.storage, &wl_ss_mint_count)
542+
}
543+
Some(3) => {
544+
let _ = WHITELIST_TS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
545+
let mut wl_ts_mint_count =
546+
WHITELIST_TS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
547+
wl_ts_mint_count += 1;
548+
WHITELIST_TS_MINT_COUNT.save(deps.storage, &wl_ts_mint_count)
549+
}
510550
_ => Err(StdError::generic_err("Invalid stage ID")),
511551
}
512552
} else {

‎contracts/minters/open-edition-minter-wl-flex/src/error.rs

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ pub enum ContractError {
3131
#[error("Invalid reply ID")]
3232
InvalidReplyID {},
3333

34+
#[error("Invalid stage ID")]
35+
InvalidStageID {},
36+
3437
#[error("Not enough funds sent")]
3538
NotEnoughFunds {},
3639

@@ -118,6 +121,9 @@ pub enum ContractError {
118121
#[error("Max minting limit per address exceeded")]
119122
MaxPerAddressLimitExceeded {},
120123

124+
#[error("WhitelistMintCountLimitReached")]
125+
WhitelistMintCountLimitReached {},
126+
121127
#[error("Token id: {token_id} already sold")]
122128
TokenIdAlreadySold { token_id: u32 },
123129

‎contracts/minters/open-edition-minter-wl-flex/src/state.rs

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub const WHITELIST_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlma");
2828
pub const WHITELIST_FS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlfsma");
2929
pub const WHITELIST_SS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlssma");
3030
pub const WHITELIST_TS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wltsma");
31+
pub const WHITELIST_FS_MINT_COUNT: Item<u32> = Item::new("wlfsmc");
32+
pub const WHITELIST_SS_MINT_COUNT: Item<u32> = Item::new("wlssmc");
33+
pub const WHITELIST_TS_MINT_COUNT: Item<u32> = Item::new("wltsmc");
3134

3235
/// This keeps track of the mint count
3336
pub const TOTAL_MINT_COUNT: Item<u32> = Item::new("total_mint_count");

‎contracts/minters/open-edition-minter/src/contract.rs

+50-9
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use crate::msg::{
66
};
77
use crate::state::{
88
increment_token_index, Config, ConfigExtension, CONFIG, MINTABLE_NUM_TOKENS, MINTER_ADDRS,
9-
SG721_ADDRESS, STATUS, TOTAL_MINT_COUNT, WHITELIST_FS_MINTER_ADDRS, WHITELIST_MINTER_ADDRS,
10-
WHITELIST_SS_MINTER_ADDRS, WHITELIST_TS_MINTER_ADDRS,
9+
SG721_ADDRESS, STATUS, TOTAL_MINT_COUNT, WHITELIST_FS_MINTER_ADDRS, WHITELIST_FS_MINT_COUNT,
10+
WHITELIST_MINTER_ADDRS, WHITELIST_SS_MINTER_ADDRS, WHITELIST_SS_MINT_COUNT,
11+
WHITELIST_TS_MINTER_ADDRS, WHITELIST_TS_MINT_COUNT,
1112
};
1213
#[cfg(not(feature = "library"))]
1314
use cosmwasm_std::entry_point;
@@ -26,7 +27,7 @@ use sg2::query::Sg2QueryMsg;
2627
use sg4::{MinterConfig, Status, StatusResponse, SudoMsg};
2728
use sg721::{ExecuteMsg as Sg721ExecuteMsg, InstantiateMsg as Sg721InstantiateMsg};
2829
use sg_std::StargazeMsgWrapper;
29-
use sg_tiered_whitelist::msg::QueryMsg as TieredWhitelistQueryMsg;
30+
use sg_tiered_whitelist::msg::{QueryMsg as TieredWhitelistQueryMsg, StageResponse};
3031
use sg_whitelist::msg::{
3132
ConfigResponse as WhitelistConfigResponse, HasMemberResponse, QueryMsg as WhitelistQueryMsg,
3233
};
@@ -410,12 +411,34 @@ fn is_public_mint(deps: Deps, info: &MessageInfo) -> Result<bool, ContractError>
410411
});
411412
}
412413

413-
// Check wl per address limit
414-
let wl_mint_count = whitelist_mint_count(deps, info, whitelist.clone())?.0;
415-
if wl_mint_count >= wl_config.per_address_limit {
414+
let wl_mint_count = whitelist_mint_count(deps, info, whitelist.clone())?;
415+
416+
// Check if whitelist per address limit is reached
417+
if wl_mint_count.0 >= wl_config.per_address_limit {
416418
return Err(ContractError::MaxPerAddressLimitExceeded {});
417419
}
418420

421+
// Check if whitelist stage mint count limit is reached
422+
if wl_mint_count.1 && wl_mint_count.2.is_some() {
423+
let active_stage: StageResponse = deps.querier.query_wasm_smart(
424+
whitelist.clone(),
425+
&TieredWhitelistQueryMsg::Stage {
426+
stage_id: wl_mint_count.2.unwrap() - 1,
427+
},
428+
)?;
429+
if active_stage.stage.mint_count_limit.is_some() {
430+
let stage_mint_count = match wl_mint_count.2.unwrap() {
431+
1 => WHITELIST_FS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
432+
2 => WHITELIST_SS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
433+
3 => WHITELIST_TS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0),
434+
_ => return Err(ContractError::InvalidStageID {}),
435+
};
436+
if stage_mint_count >= active_stage.stage.mint_count_limit.unwrap() {
437+
return Err(ContractError::WhitelistMintCountLimitReached {});
438+
}
439+
}
440+
}
441+
419442
Ok(false)
420443
}
421444

@@ -489,9 +512,27 @@ fn save_whitelist_mint_count(
489512
) -> StdResult<()> {
490513
if is_tiered_whitelist & stage_id.is_some() {
491514
match stage_id {
492-
Some(1) => WHITELIST_FS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
493-
Some(2) => WHITELIST_SS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
494-
Some(3) => WHITELIST_TS_MINTER_ADDRS.save(deps.storage, &info.sender, &count),
515+
Some(1) => {
516+
let _ = WHITELIST_FS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
517+
let mut wl_fs_mint_count =
518+
WHITELIST_FS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
519+
wl_fs_mint_count += 1;
520+
WHITELIST_FS_MINT_COUNT.save(deps.storage, &wl_fs_mint_count)
521+
}
522+
Some(2) => {
523+
let _ = WHITELIST_SS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
524+
let mut wl_ss_mint_count =
525+
WHITELIST_SS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
526+
wl_ss_mint_count += 1;
527+
WHITELIST_SS_MINT_COUNT.save(deps.storage, &wl_ss_mint_count)
528+
}
529+
Some(3) => {
530+
let _ = WHITELIST_TS_MINTER_ADDRS.save(deps.storage, &info.sender, &count);
531+
let mut wl_ts_mint_count =
532+
WHITELIST_TS_MINT_COUNT.may_load(deps.storage)?.unwrap_or(0);
533+
wl_ts_mint_count += 1;
534+
WHITELIST_TS_MINT_COUNT.save(deps.storage, &wl_ts_mint_count)
535+
}
495536
_ => Err(StdError::generic_err("Invalid stage ID")),
496537
}
497538
} else {

‎contracts/minters/open-edition-minter/src/error.rs

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ pub enum ContractError {
3131
#[error("Invalid reply ID")]
3232
InvalidReplyID {},
3333

34+
#[error("Invalid stage ID")]
35+
InvalidStageID {},
36+
3437
#[error("Not enough funds sent")]
3538
NotEnoughFunds {},
3639

@@ -118,6 +121,9 @@ pub enum ContractError {
118121
#[error("Max minting limit per address exceeded")]
119122
MaxPerAddressLimitExceeded {},
120123

124+
#[error("WhitelistMintCountLimitReached")]
125+
WhitelistMintCountLimitReached {},
126+
121127
#[error("Token id: {token_id} already sold")]
122128
TokenIdAlreadySold { token_id: u32 },
123129

‎contracts/minters/open-edition-minter/src/state.rs

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub const WHITELIST_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlma");
2727
pub const WHITELIST_FS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlfsma");
2828
pub const WHITELIST_SS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wlssma");
2929
pub const WHITELIST_TS_MINTER_ADDRS: Map<&Addr, u32> = Map::new("wltsma");
30+
pub const WHITELIST_FS_MINT_COUNT: Item<u32> = Item::new("wlfsmc");
31+
pub const WHITELIST_SS_MINT_COUNT: Item<u32> = Item::new("wlssmc");
32+
pub const WHITELIST_TS_MINT_COUNT: Item<u32> = Item::new("wltsmc");
3033

3134
/// This keeps track of the mint count
3235
pub const TOTAL_MINT_COUNT: Item<u32> = Item::new("total_mint_count");

0 commit comments

Comments
 (0)
Please sign in to comment.