use super::{
events::DisplayEvents,
name_value_println,
parse_code_hash,
runtime_api::api::{
self,
contracts::events::CodeRemoved,
},
submit_extrinsic,
Client,
CodeHash,
ContractMessageTranscoder,
DefaultConfig,
ErrorVariant,
ExtrinsicOpts,
TokenMetadata,
};
use anyhow::Result;
use std::fmt::Debug;
use subxt::{
Config,
OnlineClient,
};
use subxt_signer::sr25519::Keypair;
use tokio::runtime::Runtime;
#[derive(Debug, clap::Args)]
#[clap(name = "remove", about = "Remove a contract's code")]
pub struct RemoveCommand {
#[clap(long, value_parser = parse_code_hash)]
code_hash: Option<<DefaultConfig as Config>::Hash>,
#[clap(flatten)]
extrinsic_opts: ExtrinsicOpts,
#[clap(long, conflicts_with = "verbose")]
output_json: bool,
}
impl RemoveCommand {
pub fn is_json(&self) -> bool {
self.output_json
}
pub fn run(&self) -> Result<(), ErrorVariant> {
let artifacts = self.extrinsic_opts.contract_artifacts()?;
let transcoder = artifacts.contract_transcoder()?;
let signer = self.extrinsic_opts.signer()?;
let artifacts_path = artifacts.artifact_path().to_path_buf();
let final_code_hash = match (self.code_hash.as_ref(), artifacts.code.as_ref()) {
(Some(code_h), _) => {
Ok(code_h.0)
}
(None, Some(_)) => {
artifacts.code_hash()
}
(None, None) => {
Err(anyhow::anyhow!(
"No code_hash was provided or contract code was not found from artifact \
file {}. Please provide a code hash with --code-hash argument or specify the \
path for artifacts files with --manifest-path",
artifacts_path.display()
))
}
}?;
Runtime::new()?.block_on(async {
let url = self.extrinsic_opts.url_to_string();
let client = OnlineClient::from_url(url.clone()).await?;
if let Some(code_removed) = self
.remove_code(
&client,
sp_core::H256(final_code_hash),
&signer,
&transcoder,
)
.await?
{
let remove_result = code_removed.code_hash;
if self.output_json {
println!("{}", &remove_result);
} else {
name_value_println!("Code hash", format!("{remove_result:?}"));
}
Result::<(), ErrorVariant>::Ok(())
} else {
let error_code_hash = hex::encode(final_code_hash);
Err(anyhow::anyhow!(
"Error removing the code for the supplied code hash: {}",
error_code_hash
)
.into())
}
})
}
async fn remove_code(
&self,
client: &Client,
code_hash: CodeHash,
signer: &Keypair,
transcoder: &ContractMessageTranscoder,
) -> Result<Option<CodeRemoved>, ErrorVariant> {
let call = api::tx()
.contracts()
.remove_code(sp_core::H256(code_hash.0));
let result = submit_extrinsic(client, &call, signer).await?;
let display_events =
DisplayEvents::from_events(&result, Some(transcoder), &client.metadata())?;
let output = if self.output_json {
display_events.to_json()?
} else {
let token_metadata = TokenMetadata::query(client).await?;
display_events
.display_events(self.extrinsic_opts.verbosity()?, &token_metadata)?
};
println!("{output}");
let code_removed = result.find_first::<CodeRemoved>()?;
Ok(code_removed)
}
}