contract_extrinsics/
remove.rs

1// Copyright (C) Use Ink (UK) Ltd.
2// This file is part of cargo-contract.
3//
4// cargo-contract is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// cargo-contract is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with cargo-contract.  If not, see <http://www.gnu.org/licenses/>.
16
17use super::{
18    events::CodeRemoved,
19    submit_extrinsic,
20    ContractMessageTranscoder,
21    ErrorVariant,
22};
23use crate::{
24    extrinsic_calls::RemoveCode,
25    extrinsic_opts::ExtrinsicOpts,
26};
27
28use anyhow::Result;
29use ink_env::Environment;
30use subxt::{
31    backend::{
32        legacy::LegacyRpcMethods,
33        rpc::RpcClient,
34    },
35    blocks::ExtrinsicEvents,
36    config::{
37        DefaultExtrinsicParams,
38        ExtrinsicParams,
39    },
40    ext::{
41        scale_decode::IntoVisitor,
42        scale_encode::EncodeAsType,
43    },
44    tx,
45    Config,
46    OnlineClient,
47};
48
49/// A builder for the remove command.
50pub struct RemoveCommandBuilder<C: Config, E: Environment, Signer: Clone> {
51    code_hash: Option<C::Hash>,
52    extrinsic_opts: ExtrinsicOpts<C, E, Signer>,
53}
54
55impl<C: Config, E: Environment, Signer> RemoveCommandBuilder<C, E, Signer>
56where
57    Signer: tx::Signer<C> + Clone,
58{
59    /// Returns a clean builder for [`RemoveExec`].
60    pub fn new(
61        extrinsic_opts: ExtrinsicOpts<C, E, Signer>,
62    ) -> RemoveCommandBuilder<C, E, Signer> {
63        RemoveCommandBuilder {
64            code_hash: None,
65            extrinsic_opts,
66        }
67    }
68
69    /// Sets the hash of the smart contract code already uploaded to the chain.
70    pub fn code_hash(self, code_hash: Option<C::Hash>) -> Self {
71        let mut this = self;
72        this.code_hash = code_hash;
73        this
74    }
75}
76
77impl<C: Config, E: Environment, Signer> RemoveCommandBuilder<C, E, Signer>
78where
79    C::Hash: From<[u8; 32]>,
80    Signer: tx::Signer<C> + Clone,
81{
82    /// Preprocesses contract artifacts and options for subsequent removal of contract
83    /// code.
84    ///
85    /// This function prepares the necessary data for removing contract code based on the
86    /// provided contract artifacts and options. It ensures that the required code hash is
87    /// available and sets up the client, signer, and other relevant parameters for the
88    /// contract code removal operation.
89    ///
90    /// Returns the `RemoveExec` containing the preprocessed data for the contract code
91    /// removal, or an error in case of failure.
92    pub async fn done(self) -> Result<RemoveExec<C, E, Signer>> {
93        let artifacts = self.extrinsic_opts.contract_artifacts()?;
94        let transcoder = artifacts.contract_transcoder()?;
95
96        let artifacts_path = artifacts.artifact_path().to_path_buf();
97
98        let final_code_hash = match (self.code_hash.as_ref(), artifacts.code.as_ref()) {
99            (Some(code_h), _) => Ok(*code_h),
100            (None, Some(_)) => artifacts.code_hash().map(|h| h.into() ),
101            (None, None) => Err(anyhow::anyhow!(
102                "No code_hash was provided or contract code was not found from artifact \
103                file {}. Please provide a code hash with --code-hash argument or specify the \
104                path for artifacts files with --manifest-path",
105                artifacts_path.display()
106            )),
107        }?;
108
109        let url = self.extrinsic_opts.url();
110        let rpc_cli = RpcClient::from_url(&url).await?;
111        let client = OnlineClient::<C>::from_rpc_client(rpc_cli.clone()).await?;
112        let rpc = LegacyRpcMethods::<C>::new(rpc_cli);
113
114        Ok(RemoveExec {
115            final_code_hash,
116            opts: self.extrinsic_opts,
117            rpc,
118            client,
119            transcoder,
120        })
121    }
122}
123
124pub struct RemoveExec<C: Config, E: Environment, Signer: Clone> {
125    final_code_hash: C::Hash,
126    opts: ExtrinsicOpts<C, E, Signer>,
127    rpc: LegacyRpcMethods<C>,
128    client: OnlineClient<C>,
129    transcoder: ContractMessageTranscoder,
130}
131
132impl<C: Config, E: Environment, Signer> RemoveExec<C, E, Signer>
133where
134    C::Hash: IntoVisitor + EncodeAsType,
135    C::AccountId: IntoVisitor,
136    <C::ExtrinsicParams as ExtrinsicParams<C>>::Params:
137        From<<DefaultExtrinsicParams<C> as ExtrinsicParams<C>>::Params>,
138    Signer: tx::Signer<C> + Clone,
139{
140    /// Removes a contract code from the blockchain.
141    ///
142    /// This function removes a contract code with the specified code hash from the
143    /// blockchain, ensuring that it's no longer available for instantiation or
144    /// execution. It interacts with the blockchain's runtime API to execute the
145    /// removal operation and provides the resulting events from the removal.
146    ///
147    /// Returns the `RemoveResult` containing the events generated from the contract
148    /// code removal, or an error in case of failure.
149    pub async fn remove_code(&self) -> Result<RemoveResult<C, E>, ErrorVariant>
150    where
151        E::Balance: IntoVisitor + Into<u128>,
152    {
153        let code_hash = self.final_code_hash;
154
155        let call = RemoveCode::new(code_hash).build();
156
157        let events =
158            submit_extrinsic(&self.client, &self.rpc, &call, self.opts.signer()).await?;
159
160        let code_removed =
161            events.find_first::<CodeRemoved<C::Hash, C::AccountId, E::Balance>>()?;
162        Ok(RemoveResult {
163            code_removed,
164            events,
165        })
166    }
167
168    /// Returns the final code hash.
169    pub fn final_code_hash(&self) -> C::Hash {
170        self.final_code_hash
171    }
172
173    /// Returns the extrinsic options.
174    pub fn opts(&self) -> &ExtrinsicOpts<C, E, Signer> {
175        &self.opts
176    }
177
178    /// Returns the client.
179    pub fn client(&self) -> &OnlineClient<C> {
180        &self.client
181    }
182
183    /// Returns the contract message transcoder.
184    pub fn transcoder(&self) -> &ContractMessageTranscoder {
185        &self.transcoder
186    }
187}
188
189/// A struct representing the result of an remove command execution.
190pub struct RemoveResult<C: Config, E: Environment> {
191    pub code_removed: Option<CodeRemoved<C::Hash, C::AccountId, E::Balance>>,
192    pub events: ExtrinsicEvents<C>,
193}