1#[cfg(not(feature = "library"))]
2use cosmwasm_std::entry_point;
3use cosmwasm_std::{
4 ensure, ensure_eq, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, StdError,
5 StdResult, WasmMsg,
6};
7use cw2::set_contract_version;
8use cw_utils::must_pay;
9use semver::Version;
10use sg1::{checked_fair_burn, transfer_funds_to_launchpad_dao};
11use sg2::msg::UpdateMinterParamsMsg;
12use sg2::query::{AllowedCollectionCodeIdResponse, AllowedCollectionCodeIdsResponse, Sg2QueryMsg};
13use sg2::MinterParams;
14use sg_std::{Response, NATIVE_DENOM};
15
16use crate::error::ContractError;
17use crate::msg::{
18 BaseMinterCreateMsg, BaseSudoMsg, BaseUpdateParamsMsg, ExecuteMsg, InstantiateMsg,
19 ParamsResponse, SudoMsg,
20};
21use crate::state::SUDO_PARAMS;
22
23const CONTRACT_NAME: &str = "crates.io:sg-base-factory";
25const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
26
27#[cfg_attr(not(feature = "library"), entry_point)]
29pub fn instantiate(
30 deps: DepsMut,
31 _env: Env,
32 _info: MessageInfo,
33 msg: InstantiateMsg,
34) -> Result<Response, ContractError> {
35 set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
36
37 SUDO_PARAMS.save(deps.storage, &msg.params)?;
38
39 Ok(Response::new())
40}
41
42#[cfg_attr(not(feature = "library"), entry_point)]
43pub fn execute(
44 deps: DepsMut,
45 env: Env,
46 info: MessageInfo,
47 msg: ExecuteMsg,
48) -> Result<Response, ContractError> {
49 match msg {
50 ExecuteMsg::CreateMinter(msg) => execute_create_minter(deps, env, info, msg),
51 }
52}
53
54pub fn execute_create_minter(
55 deps: DepsMut,
56 _env: Env,
57 info: MessageInfo,
58 msg: BaseMinterCreateMsg,
59) -> Result<Response, ContractError> {
60 let params = SUDO_PARAMS.load(deps.storage)?;
61 must_pay(&info, ¶ms.creation_fee.denom)?;
62 must_be_allowed_collection(deps.as_ref(), msg.collection_params.code_id)?;
63
64 must_not_be_frozen(¶ms)?;
65
66 let mut res = Response::new();
67 if params.creation_fee.denom == NATIVE_DENOM {
68 checked_fair_burn(&info, params.creation_fee.amount.u128(), None, &mut res)?;
69 } else {
70 transfer_funds_to_launchpad_dao(
71 &info,
72 params.creation_fee.amount.u128(),
73 ¶ms.creation_fee.denom,
74 &mut res,
75 )?;
76 }
77
78 let msg = WasmMsg::Instantiate {
79 admin: Some(info.sender.to_string()),
80 code_id: params.code_id,
81 msg: to_json_binary(&msg)?,
82 funds: vec![],
83 label: format!(
84 "Minter-{}-{}",
85 params.code_id,
86 msg.collection_params.name.trim()
87 ),
88 };
89
90 Ok(res
91 .add_attribute("action", "create_minter")
92 .add_message(msg))
93}
94
95pub fn must_not_be_frozen<T>(params: &MinterParams<T>) -> Result<(), ContractError> {
96 ensure!(!params.frozen, ContractError::Frozen {});
97 Ok(())
98}
99
100pub fn must_pay_exact_amount<T>(
101 params: &MinterParams<T>,
102 info: &MessageInfo,
103 accepted_denom: &str,
104) -> Result<(), ContractError> {
105 must_pay(info, accepted_denom)?;
106 ensure!(
108 info.funds[0].amount == params.creation_fee.amount,
109 ContractError::InvalidCreationFeeAmount {}
110 );
111 Ok(())
112}
113
114pub fn must_be_allowed_collection(deps: Deps, code_id: u64) -> Result<(), ContractError> {
115 let res = query_allowed_collection_code_id(deps, code_id)?;
116 if !res.allowed {
117 return Err(ContractError::InvalidCollectionCodeId { code_id });
118 }
119 Ok(())
120}
121
122#[cfg_attr(not(feature = "library"), entry_point)]
123pub fn sudo(deps: DepsMut, env: Env, msg: BaseSudoMsg) -> Result<Response, ContractError> {
124 match msg {
125 SudoMsg::UpdateParams(params_msg) => sudo_update_params(deps, env, *params_msg),
126 }
127}
128
129pub fn sudo_update_params(
131 deps: DepsMut,
132 _env: Env,
133 param_msg: BaseUpdateParamsMsg,
134) -> Result<Response, ContractError> {
135 let mut params = SUDO_PARAMS.load(deps.storage)?;
136
137 update_params(&mut params, param_msg)?;
138
139 SUDO_PARAMS.save(deps.storage, ¶ms)?;
140
141 Ok(Response::new().add_attribute("action", "sudo_update_params"))
142}
143
144pub fn update_params<T, C>(
146 params: &mut MinterParams<C>,
147 param_msg: UpdateMinterParamsMsg<T>,
148) -> Result<(), ContractError> {
149 params.code_id = param_msg.code_id.unwrap_or(params.code_id);
150
151 if let Some(frozen) = param_msg.frozen {
152 params.frozen = frozen;
153 }
154
155 if let Some(creation_fee) = param_msg.creation_fee {
156 params.creation_fee = creation_fee;
157 }
158
159 if let Some(min_mint_price) = param_msg.min_mint_price {
160 ensure_eq!(
161 &min_mint_price.denom,
162 &NATIVE_DENOM,
163 ContractError::InvalidDenom {}
164 );
165 params.min_mint_price = min_mint_price;
166 }
167
168 if let Some(add_sg721_code_ids) = param_msg.add_sg721_code_ids {
170 for code_id in add_sg721_code_ids {
171 params.allowed_sg721_code_ids.push(code_id);
172 }
173 }
174 params.allowed_sg721_code_ids.dedup();
175 if let Some(rm_sg721_code_ids) = param_msg.rm_sg721_code_ids {
176 for code_id in rm_sg721_code_ids {
177 params.allowed_sg721_code_ids.retain(|&x| x != code_id);
178 }
179 }
180
181 params.mint_fee_bps = param_msg.mint_fee_bps.unwrap_or(params.mint_fee_bps);
182
183 params.max_trading_offset_secs = param_msg
184 .max_trading_offset_secs
185 .unwrap_or(params.max_trading_offset_secs);
186
187 Ok(())
188}
189
190#[cfg_attr(not(feature = "library"), entry_point)]
191pub fn query(deps: Deps, _env: Env, msg: Sg2QueryMsg) -> StdResult<Binary> {
192 match msg {
193 Sg2QueryMsg::Params {} => to_json_binary(&query_params(deps)?),
194 Sg2QueryMsg::AllowedCollectionCodeIds {} => {
195 to_json_binary(&query_allowed_collection_code_ids(deps)?)
196 }
197 Sg2QueryMsg::AllowedCollectionCodeId(code_id) => {
198 to_json_binary(&query_allowed_collection_code_id(deps, code_id)?)
199 }
200 }
201}
202
203fn query_params(deps: Deps) -> StdResult<ParamsResponse> {
204 let params = SUDO_PARAMS.load(deps.storage)?;
205 Ok(ParamsResponse { params })
206}
207
208fn query_allowed_collection_code_ids(deps: Deps) -> StdResult<AllowedCollectionCodeIdsResponse> {
209 let params = SUDO_PARAMS.load(deps.storage)?;
210 let code_ids = params.allowed_sg721_code_ids;
211 Ok(AllowedCollectionCodeIdsResponse { code_ids })
212}
213
214fn query_allowed_collection_code_id(
215 deps: Deps,
216 code_id: u64,
217) -> StdResult<AllowedCollectionCodeIdResponse> {
218 let params = SUDO_PARAMS.load(deps.storage)?;
219 let code_ids = params.allowed_sg721_code_ids;
220 let allowed = code_ids.contains(&code_id);
221 Ok(AllowedCollectionCodeIdResponse { allowed })
222}
223
224#[cfg_attr(not(feature = "library"), entry_point)]
225pub fn migrate(
226 deps: DepsMut,
227 _env: Env,
228 msg: Option<BaseUpdateParamsMsg>,
229) -> Result<Response, ContractError> {
230 let prev_contract_info = cw2::get_contract_version(deps.storage)?;
231 let prev_contract_name: String = prev_contract_info.contract;
232 let prev_contract_version: Version = prev_contract_info
233 .version
234 .parse()
235 .map_err(|_| StdError::generic_err("Unable to retrieve previous contract version"))?;
236
237 let new_version: Version = CONTRACT_VERSION
238 .parse()
239 .map_err(|_| StdError::generic_err("Invalid contract version"))?;
240
241 if prev_contract_name != CONTRACT_NAME {
242 return Err(StdError::generic_err("Cannot migrate to a different contract").into());
243 }
244
245 if prev_contract_version > new_version {
246 return Err(StdError::generic_err("Cannot migrate to a previous contract version").into());
247 }
248
249 if let Some(msg) = msg {
250 let mut params = SUDO_PARAMS.load(deps.storage)?;
251
252 update_params(&mut params, msg)?;
253
254 SUDO_PARAMS.save(deps.storage, ¶ms)?;
255 }
256
257 Ok(Response::new().add_attribute("action", "migrate"))
258}