1use cosmwasm_std::{DepsMut, Empty, Env, MessageInfo, Never, Response};
2
3pub const CHECKSUM: [u8; 32] = [
6 95, 107, 196, 86, 230, 56, 249, 93, 219, 111, 197, 12, 17, 82, 18, 222, 186, 194, 177, 42, 25,
7 7, 208, 121, 178, 254, 148, 61, 239, 125, 113, 217,
8];
9
10#[cfg_attr(not(feature = "library"), cosmwasm_std::entry_point)]
11pub fn instantiate(_: DepsMut, _: Env, _: MessageInfo, _: Empty) -> Result<Response, Never> {
12 Ok(Response::new())
13}
14
15#[cfg(not(target_arch = "wasm32"))]
16pub mod interface {
17 use super::*;
18
19 use cosmwasm_std::{
20 instantiate2_address, Binary, CanonicalAddr, Checksum, Instantiate2AddressError,
21 };
22 use cw_orch::{contract::Contract, prelude::*};
23
24 #[derive(Clone)]
26 pub struct CwBlob<Chain>(Contract<Chain>);
27
28 impl<Chain> CwBlob<Chain> {
29 pub fn new(contract_id: impl ToString, chain: Chain) -> Self {
30 Self(Contract::new(contract_id, chain))
31 }
32 }
33
34 impl<Chain: ChainState> ContractInstance<Chain> for CwBlob<Chain> {
35 fn as_instance(&self) -> &Contract<Chain> {
36 &self.0
37 }
38
39 fn as_instance_mut(&mut self) -> &mut Contract<Chain> {
40 &mut self.0
41 }
42 }
43
44 impl<T: CwEnv> Uploadable for CwBlob<T> {
45 fn wasm(_chain: &ChainInfoOwned) -> WasmPath {
46 wasm_path()
47 }
48
49 fn wrapper() -> Box<dyn MockContract<Empty, Empty>> {
50 Box::new(
51 ContractWrapper::new_with_empty(
52 |_, _, _, _: Empty| -> Result<Response, Never> { unreachable!() },
53 super::instantiate,
54 |_, _, _: Empty| -> Result<Binary, Never> { unreachable!() },
55 )
56 .with_checksum(checksum()),
57 )
58 }
59 }
60
61 pub fn checksum() -> Checksum {
62 Checksum::from(CHECKSUM)
63 }
64
65 pub(crate) fn wasm_path() -> WasmPath {
66 artifacts_dir_from_workspace!()
67 .find_wasm_path("cw_blob")
68 .unwrap()
69 }
70
71 pub trait DeterministicInstantiation<Chain: CwEnv>:
72 ContractInstance<Chain> + CwOrchUpload<Chain> + MigratableContract
73 {
74 fn deterministic_instantiate(
79 &self,
80 migrate_msg: &Self::MigrateMsg,
81 blob_code_id: u64,
83 expected_addr: CanonicalAddr,
84 salt: Binary,
85 ) -> Result<(), CwOrchError> {
86 let chain = self.environment();
87 let on_chain_checksum = chain
88 .wasm_querier()
89 .code_id_hash(blob_code_id)
90 .map_err(Into::into)?;
91 let creator = chain.sender_addr();
92 let label = self.id();
93
94 {
96 let expected_checksum = checksum();
97 if on_chain_checksum != expected_checksum {
98 return Err(CwOrchError::StdErr(format!(
99 "Expected blob checksum: {expected_checksum}, stored under given code_id: {on_chain_checksum}"
100 )));
101 }
102 }
103
104 {
106 let actual_addr = self.deterministic_address(&salt)?;
107 if actual_addr != expected_addr {
108 return Err(CwOrchError::StdErr(
109 "Predicted blob address doesn't match to the expected".to_owned(),
110 ));
111 }
112 }
113
114 let response = chain
115 .instantiate2(
116 blob_code_id,
117 &cosmwasm_std::Empty {},
118 Some(&label),
119 Some(&creator),
120 &[],
121 salt,
122 )
123 .map_err(Into::into)?;
124 let blob_address = response.instantiated_contract_address()?;
125 let blob_cosmrs_account_id: cosmrs::AccountId = blob_address.as_str().parse().unwrap();
126 if blob_cosmrs_account_id.to_bytes() != expected_addr.as_slice() {
127 panic!("Unexpected error: Instantiated blob address doesn't match to the expected");
130 }
131
132 self.upload_if_needed()?;
133 let contract_code_id = self.code_id()?;
134 self.set_address(&blob_address);
135 self.migrate(migrate_msg, contract_code_id)?;
136 Ok(())
137 }
138
139 fn deterministic_address(
140 &self,
141 salt: &Binary,
142 ) -> Result<CanonicalAddr, Instantiate2AddressError> {
143 let creator = self.environment().sender_addr();
144 let account_id: cosmrs::AccountId = creator.as_str().parse().unwrap();
145 let canon_creator = CanonicalAddr::from(account_id.to_bytes());
146 let actual_addr =
147 instantiate2_address(checksum().as_slice(), &canon_creator, salt.as_slice())?;
148 Ok(actual_addr)
149 }
150 }
151}
152
153#[cfg(test)]
154mod test {
155 use interface::{checksum, wasm_path};
156
157 use super::*;
158
159 #[test]
160 fn test_checksum() {
161 let checksum = checksum();
162 let expected_checksum = wasm_path().checksum().unwrap();
163 assert_eq!(checksum, expected_checksum);
164 }
165}