Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mint hooks to vending minter #628

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion contracts/minters/vending-minter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@ sg-whitelist = { workspace = true, features = ["library"] }
thiserror = { workspace = true }
url = { workspace = true }
vending-factory = { workspace = true, features = ["library"] }
semver = {workspace = true }
semver = { workspace = true }
sg-mint-hooks = { workspace = true }
sg-controllers = { workspace = true }
42 changes: 42 additions & 0 deletions contracts/minters/vending-minter/schema/execute_msg.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,48 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"add_pre_mint_hook"
],
"properties": {
"add_pre_mint_hook": {
"type": "object",
"required": [
"hook"
],
"properties": {
"hook": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"add_post_mint_hook"
],
"properties": {
"add_post_mint_hook": {
"type": "object",
"required": [
"hook"
],
"properties": {
"hook": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
Expand Down
26 changes: 26 additions & 0 deletions contracts/minters/vending-minter/schema/query_msg.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,32 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"pre_mint_hooks"
],
"properties": {
"pre_mint_hooks": {
"type": "object",
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"post_mint_hooks"
],
"properties": {
"post_mint_hooks": {
"type": "object",
"additionalProperties": false
}
},
"additionalProperties": false
}
]
}
117 changes: 58 additions & 59 deletions contracts/minters/vending-minter/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
use sg2::query::Sg2QueryMsg;
use sg4::{MinterConfig, Status, StatusResponse, SudoMsg};
use sg721::{ExecuteMsg as Sg721ExecuteMsg, InstantiateMsg as Sg721InstantiateMsg};
use sg_mint_hooks::post::{add_postmint_hook, prepare_postmint_hooks};
use sg_mint_hooks::pre::{add_premint_hook, prepare_premint_hooks};
use sg_std::{StargazeMsgWrapper, GENESIS_MINT_START_TIME, NATIVE_DENOM};
use sg_whitelist::msg::{
ConfigResponse as WhitelistConfigResponse, HasMemberResponse, QueryMsg as WhitelistQueryMsg,
Expand Down Expand Up @@ -240,6 +242,14 @@
execute_update_discount_price(deps, env, info, price)
}
ExecuteMsg::RemoveDiscountPrice {} => execute_remove_discount_price(deps, info),
ExecuteMsg::AddPreMintHook { hook } => {
only_admin(deps.as_ref(), &info)?;
add_premint_hook(deps, hook).map_err(ContractError::from)

Check warning on line 247 in contracts/minters/vending-minter/src/contract.rs

View check run for this annotation

Codecov / codecov/patch

contracts/minters/vending-minter/src/contract.rs#L245-L247

Added lines #L245 - L247 were not covered by tests
}
ExecuteMsg::AddPostMintHook { hook } => {
only_admin(deps.as_ref(), &info)?;
add_postmint_hook(deps, hook).map_err(ContractError::from)

Check warning on line 251 in contracts/minters/vending-minter/src/contract.rs

View check run for this annotation

Codecov / codecov/patch

contracts/minters/vending-minter/src/contract.rs#L249-L251

Added lines #L249 - L251 were not covered by tests
}
}
}

Expand All @@ -250,12 +260,10 @@
price: u128,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
only_admin(deps.as_ref(), &info)?;

let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}

if env.block.time < config.extension.start_time {
return Err(ContractError::BeforeMintStartTime {});
}
Expand Down Expand Up @@ -294,12 +302,9 @@
info: MessageInfo,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
only_admin(deps.as_ref(), &info)?;

let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}
config.extension.discount_price = None;
CONFIG.save(deps.storage, &config)?;

Expand Down Expand Up @@ -391,22 +396,19 @@
whitelist: &str,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
only_admin(deps.as_ref(), &info)?;

let mut config = CONFIG.load(deps.storage)?;
let MinterConfig {
factory,
extension:
ConfigExtension {
whitelist: existing_whitelist,
admin,
start_time,
..
},
..
} = config.clone();
ensure!(
admin == info.sender,
ContractError::Unauthorized("Sender is not an admin".to_owned())
);

ensure!(
env.block.time < start_time,
Expand Down Expand Up @@ -547,17 +549,11 @@
info: MessageInfo,
recipient: String,
) -> Result<Response, ContractError> {
only_admin(deps.as_ref(), &info)?;

let recipient = deps.api.addr_validate(&recipient)?;
let config = CONFIG.load(deps.storage)?;
let action = "mint_to";

// Check only admin
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}

_execute_mint(deps, env, info, action, true, Some(recipient), None)
}

Expand All @@ -568,17 +564,11 @@
token_id: u32,
recipient: String,
) -> Result<Response, ContractError> {
only_admin(deps.as_ref(), &info)?;

let recipient = deps.api.addr_validate(&recipient)?;
let config = CONFIG.load(deps.storage)?;
let action = "mint_for";

// Check only admin
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}

_execute_mint(
deps,
env,
Expand Down Expand Up @@ -684,6 +674,14 @@
None => random_mintable_token_mapping(deps.as_ref(), env, info.sender.clone())?,
};

let premint_hooks = prepare_premint_hooks(
deps.as_ref(),
sg721_address.clone(),
Some(mintable_token_mapping.token_id.to_string()),
info.sender.to_string(),
)?;
res = res.add_submessages(premint_hooks);

// Create mint msgs
let mint_msg = Sg721ExecuteMsg::<Extension, Empty>::Mint {
token_id: mintable_token_mapping.token_id.to_string(),
Expand All @@ -701,6 +699,14 @@
});
res = res.add_message(msg);

let postmint_hooks = prepare_postmint_hooks(
deps.as_ref(),
sg721_address,
Some(mintable_token_mapping.token_id.to_string()),
info.sender.to_string(),
)?;
res = res.add_submessages(postmint_hooks);

// Remove mintable token position from map
MINTABLE_TOKEN_POSITIONS.remove(deps.storage, mintable_token_mapping.position);
let mintable_num_tokens = MINTABLE_NUM_TOKENS.load(deps.storage)?;
Expand Down Expand Up @@ -814,12 +820,9 @@
price: u128,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
only_admin(deps.as_ref(), &info)?;

let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}
// If current time is after the stored start time, only allow lowering price
if env.block.time >= config.extension.start_time && price >= config.mint_price.amount.u128() {
return Err(ContractError::UpdatedMintPriceTooHigh {
Expand Down Expand Up @@ -855,12 +858,9 @@
start_time: Timestamp,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
only_admin(deps.as_ref(), &info)?;

let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}
// If current time is after the stored start time return error
if env.block.time >= config.extension.start_time {
return Err(ContractError::AlreadyStarted {});
Expand Down Expand Up @@ -892,15 +892,11 @@
start_time: Option<Timestamp>,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
only_admin(deps.as_ref(), &info)?;

let config = CONFIG.load(deps.storage)?;
let sg721_contract_addr = SG721_ADDRESS.load(deps.storage)?;

if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}

// add custom rules here
let factory_params: ParamsResponse = deps
.querier
Expand Down Expand Up @@ -948,12 +944,9 @@
per_address_limit: u32,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
only_admin(deps.as_ref(), &info)?;

let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}

let factory: ParamsResponse = deps
.querier
Expand Down Expand Up @@ -999,13 +992,7 @@
info: MessageInfo,
) -> Result<Response, ContractError> {
nonpayable(&info)?;
let config = CONFIG.load(deps.storage)?;
// Check only admin
if info.sender != config.extension.admin {
return Err(ContractError::Unauthorized(
"Sender is not an admin".to_owned(),
));
}
only_admin(deps.as_ref(), &info)?;

// check mint not sold out
let mintable_num_tokens = MINTABLE_NUM_TOKENS.load(deps.storage)?;
Expand Down Expand Up @@ -1088,6 +1075,14 @@
Ok(three_percent as u32)
}

fn only_admin(deps: Deps, info: &MessageInfo) -> Result<(), ContractError> {
ensure!(
CONFIG.load(deps.storage)?.extension.admin == info.sender,
ContractError::Unauthorized("Sender is not an admin".to_owned())
);
Ok(())
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn sudo(deps: DepsMut, _env: Env, msg: SudoMsg) -> Result<Response, ContractError> {
match msg {
Expand Down Expand Up @@ -1125,6 +1120,8 @@
QueryMsg::MintableNumTokens {} => to_binary(&query_mintable_num_tokens(deps)?),
QueryMsg::MintPrice {} => to_binary(&query_mint_price(deps)?),
QueryMsg::MintCount { address } => to_binary(&query_mint_count(deps, address)?),
QueryMsg::PreMintHooks {} => to_binary(&sg_mint_hooks::pre::query_premint_hooks(deps)?),
QueryMsg::PostMintHooks {} => to_binary(&sg_mint_hooks::post::query_postmint_hooks(deps)?),

Check warning on line 1124 in contracts/minters/vending-minter/src/contract.rs

View check run for this annotation

Codecov / codecov/patch

contracts/minters/vending-minter/src/contract.rs#L1123-L1124

Added lines #L1123 - L1124 were not covered by tests
}
}

Expand Down Expand Up @@ -1210,6 +1207,8 @@
// Reply callback triggered from cw721 contract instantiation
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
sg_mint_hooks::handle_reply(msg.id)?;

if msg.id != INSTANTIATE_SG721_REPLY_ID {
return Err(ContractError::InvalidReplyID {});
}
Expand Down
5 changes: 5 additions & 0 deletions contracts/minters/vending-minter/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use cosmwasm_std::{Coin, StdError, Timestamp};
use cw_utils::PaymentError;
use sg1::FeeError;
use sg_mint_hooks::MintHookError;
use thiserror::Error;
use url::ParseError;

#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Expand All @@ -17,6 +19,9 @@ pub enum ContractError {
#[error("{0}")]
Fee(#[from] FeeError),

#[error("{0}")]
MintHook(#[from] MintHookError),

#[error("Unauthorized: {0}")]
Unauthorized(String),

Expand Down
Loading
Loading