1#[cfg(not(feature = "library"))]
2use cosmwasm_std::entry_point;
3use cosmwasm_std::{
4 to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, SubMsg,
5 WasmMsg,
6};
7
8use cw2::set_contract_version;
9use cw_utils::parse_reply_instantiate_data;
10
11use crate::error::ContractError;
12use crate::msg::{AdminResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
13use crate::state::{ADMIN, EXPECT};
14
15pub(crate) const CONTRACT_NAME: &str = "crates.io:cw-admin-factory";
16pub(crate) const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
17
18pub const INSTANTIATE_CONTRACT_REPLY_ID: u64 = 0;
19pub const INSTANTIATE2_CONTRACT_REPLY_ID: u64 = 2;
20
21#[cfg_attr(not(feature = "library"), entry_point)]
22pub fn instantiate(
23 deps: DepsMut,
24 _env: Env,
25 info: MessageInfo,
26 msg: InstantiateMsg,
27) -> Result<Response, ContractError> {
28 set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
29
30 let admin = msg.admin.map(|a| deps.api.addr_validate(&a)).transpose()?;
31 ADMIN.save(deps.storage, &admin)?;
32
33 Ok(Response::new()
34 .add_attribute("method", "instantiate")
35 .add_attribute("creator", info.sender))
36}
37
38#[cfg_attr(not(feature = "library"), entry_point)]
39pub fn execute(
40 deps: DepsMut,
41 env: Env,
42 info: MessageInfo,
43 msg: ExecuteMsg,
44) -> Result<Response, ContractError> {
45 match msg {
46 ExecuteMsg::InstantiateContractWithSelfAdmin {
47 instantiate_msg: msg,
48 code_id,
49 label,
50 } => instantiate_contract(deps, env, info, msg, code_id, label),
51 ExecuteMsg::Instantiate2ContractWithSelfAdmin {
52 instantiate_msg: msg,
53 code_id,
54 label,
55 salt,
56 expect,
57 } => instantiate2_contract(deps, env, info, msg, code_id, label, salt, expect),
58 }
59}
60
61pub fn instantiate_contract(
62 deps: DepsMut,
63 env: Env,
64 info: MessageInfo,
65 instantiate_msg: Binary,
66 code_id: u64,
67 label: String,
68) -> Result<Response, ContractError> {
69 if let Some(admin) = ADMIN.load(deps.storage)? {
71 if admin != info.sender {
72 return Err(ContractError::Unauthorized {});
73 }
74 }
75
76 let instantiate = WasmMsg::Instantiate {
78 admin: Some(env.contract.address.to_string()),
79 code_id,
80 msg: instantiate_msg,
81 funds: info.funds,
82 label,
83 };
84
85 let msg = SubMsg::reply_on_success(instantiate, INSTANTIATE_CONTRACT_REPLY_ID);
86 Ok(Response::default()
87 .add_attribute("action", "instantiate_contract_with_self_admin")
88 .add_submessage(msg))
89}
90
91#[allow(clippy::too_many_arguments)]
92pub fn instantiate2_contract(
93 deps: DepsMut,
94 env: Env,
95 info: MessageInfo,
96 instantiate_msg: Binary,
97 code_id: u64,
98 label: String,
99 salt: Binary,
100 expect: Option<String>,
101) -> Result<Response, ContractError> {
102 if let Some(admin) = ADMIN.load(deps.storage)? {
104 if admin != info.sender {
105 return Err(ContractError::Unauthorized {});
106 }
107 }
108
109 if let Some(expect) = expect {
110 let expect = deps.api.addr_validate(&expect)?;
111 EXPECT.save(deps.storage, &expect)?;
112 }
113
114 let instantiate = WasmMsg::Instantiate2 {
116 admin: Some(env.contract.address.to_string()),
117 code_id,
118 msg: instantiate_msg,
119 funds: info.funds,
120 label,
121 salt,
122 };
123
124 let msg = SubMsg::reply_on_success(instantiate, INSTANTIATE2_CONTRACT_REPLY_ID);
125 Ok(Response::default()
126 .add_attribute("action", "instantiate2_contract_with_self_admin")
127 .add_submessage(msg))
128}
129
130#[cfg_attr(not(feature = "library"), entry_point)]
131pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
132 match msg {
133 QueryMsg::Admin {} => Ok(to_json_binary(&AdminResponse {
134 admin: ADMIN.load(deps.storage)?,
135 })?),
136 }
137}
138
139#[cfg_attr(not(feature = "library"), entry_point)]
140pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
141 let msg_id = msg.id;
142 match msg_id {
143 INSTANTIATE_CONTRACT_REPLY_ID | INSTANTIATE2_CONTRACT_REPLY_ID => {
144 let res = parse_reply_instantiate_data(msg)?;
145 let contract_addr = deps.api.addr_validate(&res.contract_address)?;
146
147 if msg_id == INSTANTIATE2_CONTRACT_REPLY_ID {
148 let expect = EXPECT.may_load(deps.storage)?;
150 if let Some(expect) = expect {
151 EXPECT.remove(deps.storage);
152 if contract_addr != expect {
153 return Err(ContractError::UnexpectedContractAddress {
154 expected: expect.to_string(),
155 actual: contract_addr.to_string(),
156 });
157 }
158 }
159 }
160
161 let msg = WasmMsg::UpdateAdmin {
163 contract_addr: contract_addr.to_string(),
164 admin: contract_addr.to_string(),
165 };
166
167 Ok(Response::default()
168 .add_attribute("set contract admin as itself", contract_addr)
169 .add_message(msg))
170 }
171 _ => Err(ContractError::UnknownReplyID {}),
172 }
173}
174
175#[cfg_attr(not(feature = "library"), entry_point)]
176pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
177 set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
179 Ok(Response::default())
180}