terra_rust_api/client/
wasm.rs

1use crate::client::wasm_types::{
2    WasmCodeResult, WasmContractInfoResult, WasmParameterResult, WasmQueryRawResult,
3};
4use crate::{Message, PrivateKey, Terra};
5use secp256k1::{Secp256k1, Signing};
6use std::path::Path;
7
8use crate::client::tx_types::TXResultSync;
9use crate::core_types::Coin;
10use crate::errors::TerraRustAPIError;
11use crate::messages::wasm::{MsgInstantiateContract, MsgMigrateContract, MsgStoreCode};
12use serde::Deserialize;
13
14pub struct Wasm<'a> {
15    terra: &'a Terra,
16}
17
18impl Wasm<'_> {
19    pub fn create(terra: &'_ Terra) -> Wasm<'_> {
20        Wasm { terra }
21    }
22    pub async fn codes(&self, code_id: u64) -> Result<WasmCodeResult, TerraRustAPIError> {
23        let code = self
24            .terra
25            .send_cmd::<WasmCodeResult>(&format!("/wasm/codes/{}", code_id), None)
26            .await?;
27        Ok(code)
28    }
29    pub async fn info(
30        &self,
31        contract_address: &str,
32    ) -> Result<WasmContractInfoResult, TerraRustAPIError> {
33        let code = self
34            .terra
35            .send_cmd::<WasmContractInfoResult>(
36                &format!("/wasm/contracts/{}", contract_address),
37                None,
38            )
39            .await?;
40        Ok(code)
41    }
42    pub async fn parameters(&self) -> Result<WasmParameterResult, TerraRustAPIError> {
43        let code = self
44            .terra
45            .send_cmd::<WasmParameterResult>("/wasm/parameters", None)
46            .await?;
47        Ok(code)
48    }
49    pub async fn query<T: for<'de> Deserialize<'de>>(
50        &self,
51        contract_address: &str,
52        json_query: &str,
53    ) -> Result<T, TerraRustAPIError> {
54        let code = self
55            .terra
56            .send_cmd::<T>(
57                &format!("/wasm/contracts/{}/store?", contract_address),
58                Some(&format!("query_msg={}", json_query)),
59            )
60            .await?;
61        Ok(code)
62    }
63    pub async fn query_raw(
64        &self,
65        contract_address: &str,
66        key: &str,
67        sub_key: &Option<String>,
68    ) -> Result<(String, String), TerraRustAPIError> {
69        let json_query = match sub_key {
70            Some(sub_key_str) => format!("key={}&subkey={}", key, &sub_key_str),
71            None => format!("key={}", key),
72        };
73
74        let code = self
75            .terra
76            .send_cmd::<WasmQueryRawResult>(
77                &format!("/wasm/contracts/{}/store/raw?", contract_address),
78                Some(&json_query),
79            )
80            .await?;
81        let key_vec = subtle_encoding::base64::decode(code.result.key.as_bytes())?;
82        let key = String::from_utf8(key_vec)?;
83        eprintln!("{}", code.result.key);
84        let value_vec = subtle_encoding::base64::decode(code.result.value)?;
85        let value = String::from_utf8(value_vec)?;
86
87        Ok((key, value))
88    }
89    /// store a wasm file onto the chain.
90    pub async fn store<C: Signing + Signing>(
91        &self,
92        secp: &Secp256k1<C>,
93        from: &PrivateKey,
94        wasm: &str,
95        memo: Option<String>,
96    ) -> Result<TXResultSync, TerraRustAPIError> {
97        let from_public_key = from.public_key(secp);
98
99        let wasm_path = Path::new(wasm);
100
101        let store_message = MsgStoreCode::create_from_file(&from_public_key.account()?, wasm_path)?;
102        let messages: Vec<Message> = vec![store_message];
103
104        let resp = self
105            .terra
106            .submit_transaction_sync(secp, from, messages, memo)
107            .await;
108        resp
109    }
110    /// create a contract using code_id, json init args, and optionally admin on the chain
111    #[allow(clippy::too_many_arguments)]
112    pub async fn instantiate<C: Signing + Signing>(
113        &self,
114        secp: &Secp256k1<C>,
115        from: &PrivateKey,
116        code_id: u64,
117        json: String,
118        coins: Vec<Coin>,
119        admin: Option<String>,
120        memo: Option<String>,
121    ) -> Result<TXResultSync, TerraRustAPIError> {
122        let from_public_key = from.public_key(secp);
123        let init_message = MsgInstantiateContract::create_from_json(
124            &from_public_key.account()?,
125            admin,
126            code_id,
127            &json,
128            coins,
129        )?;
130        let messages: Vec<Message> = vec![init_message];
131
132        let resp = self
133            .terra
134            .submit_transaction_sync(secp, from, messages, memo)
135            .await;
136
137        resp
138    }
139
140    /// migrate an existing contract to new_code_id, optionally with a migrate args
141    pub async fn migrate<C: Signing + Signing>(
142        &self,
143        secp: &Secp256k1<C>,
144        from: &PrivateKey,
145        contract: &str,
146        new_code_id: u64,
147        migrate: Option<String>,
148        memo: Option<String>,
149    ) -> Result<TXResultSync, TerraRustAPIError> {
150        let from_public_key = from.public_key(secp);
151
152        let migrate_message = if let Some(migrate_string) = migrate {
153            MsgMigrateContract::create_from_json(
154                &from_public_key.account()?,
155                contract,
156                new_code_id,
157                &migrate_string,
158            )?
159        } else {
160            MsgMigrateContract::create_from_json(
161                &from_public_key.account()?,
162                contract,
163                new_code_id,
164                "{}",
165            )?
166        };
167
168        let messages: Vec<Message> = vec![migrate_message];
169
170        let resp = self
171            .terra
172            .submit_transaction_sync(secp, from, messages, memo)
173            .await;
174        resp
175    }
176}