layer_climb_cli/command/
contract.rs1use anyhow::Result;
2use clap::Subcommand;
3use layer_climb::{prelude::*, proto::abci::TxResponse};
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Subcommand)]
7pub enum ContractCommand {
8 Upload {
10 #[arg(long)]
12 wasm_file: PathBuf,
13 },
14
15 Instantiate {
17 #[arg(long)]
19 code_id: u64,
20 #[arg(long)]
22 msg: Option<String>,
23 #[arg(long)]
25 label: Option<String>,
26 #[arg(long)]
28 funds_denom: Option<String>,
29 #[arg(long)]
31 funds_amount: Option<String>,
32 },
33
34 Execute {
36 #[arg(long)]
38 address: String,
39 #[arg(long)]
41 msg: Option<String>,
42 #[arg(long)]
44 funds_denom: Option<String>,
45 #[arg(long)]
47 funds_amount: Option<String>,
48 },
49
50 Query {
52 #[arg(long)]
54 address: String,
55 #[arg(long)]
57 msg: Option<String>,
58 },
59}
60
61impl ContractCommand {
62 pub async fn run(&self, client: impl Into<AnyClient>, log: impl Fn(ContractLog)) -> Result<()> {
63 let client = client.into();
64 match self {
65 ContractCommand::Upload { wasm_file } => {
66 let wasm_byte_code = tokio::fs::read(wasm_file).await?;
67 let (code_id, tx_resp) = client
68 .as_signing()
69 .contract_upload_file(wasm_byte_code, None)
70 .await?;
71
72 log(ContractLog::Upload {
73 code_id,
74 tx_resp: Box::new(tx_resp),
75 });
76 }
77 ContractCommand::Instantiate {
78 code_id,
79 msg,
80 label,
81 funds_denom,
82 funds_amount,
83 } => {
84 let (addr, tx_resp) = client
85 .as_signing()
86 .contract_instantiate(
87 client.as_signing().addr.clone(),
88 *code_id,
89 label.clone().unwrap_or_default(),
90 &contract_str_to_msg(msg.as_deref())?,
91 get_funds(
92 &client.as_querier().chain_config,
93 funds_denom.clone(),
94 funds_amount.clone(),
95 ),
96 None,
97 )
98 .await?;
99
100 log(ContractLog::Instantiate {
101 addr,
102 tx_resp: Box::new(tx_resp),
103 });
104 }
105 ContractCommand::Execute {
106 address,
107 msg,
108 funds_denom,
109 funds_amount,
110 } => {
111 let address = client.as_querier().chain_config.parse_address(address)?;
112
113 let tx_resp = client
114 .as_signing()
115 .contract_execute(
116 &address,
117 &contract_str_to_msg(msg.as_deref())?,
118 get_funds(
119 &client.as_querier().chain_config,
120 funds_denom.clone(),
121 funds_amount.clone(),
122 ),
123 None,
124 )
125 .await?;
126
127 log(ContractLog::Execute {
128 tx_resp: Box::new(tx_resp),
129 });
130 }
131 ContractCommand::Query { address, msg } => {
132 let address = client.as_querier().chain_config.parse_address(address)?;
133
134 let resp = client
135 .as_querier()
136 .contract_smart_raw(&address, &contract_str_to_msg(msg.as_deref())?)
137 .await?;
138 let resp = std::str::from_utf8(&resp)?;
139
140 log(ContractLog::Query {
141 response: resp.to_string(),
142 });
143 }
144 }
145 Ok(())
146 }
147}
148
149fn get_funds(
150 chain_config: &ChainConfig,
151 funds_denom: Option<String>,
152 funds_amount: Option<String>,
153) -> Vec<Coin> {
154 match funds_amount {
155 Some(funds_amount) => {
156 let funds_denom = funds_denom.unwrap_or(chain_config.gas_denom.clone());
157 vec![new_coin(funds_denom, funds_amount)]
158 }
159 None => Vec::new(),
160 }
161}
162
163pub enum ContractLog {
164 Upload {
165 code_id: u64,
166 tx_resp: Box<TxResponse>,
167 },
168 Instantiate {
169 addr: Address,
170 tx_resp: Box<TxResponse>,
171 },
172 Execute {
173 tx_resp: Box<TxResponse>,
174 },
175 Query {
176 response: String,
177 },
178}