zilliqa_rs/contract/
factory.rs

1use std::{path::Path, sync::Arc};
2
3use crate::{
4    core::parse_zil,
5    core::{DeployContractResponse, ZilAddress},
6    middlewares::Middleware,
7    transaction::{Transaction, TransactionBuilder, TransactionParams},
8    Error,
9};
10
11use super::{compress_contract, BaseContract, Init};
12
13pub struct Factory<T: Middleware> {
14    client: Arc<T>,
15}
16
17impl<T: Middleware> Factory<T> {
18    pub fn new(client: Arc<T>) -> Self {
19        Self { client }
20    }
21
22    /// The `deploy_from_file` function deploys a contract from a file path, with the option to override
23    /// transaction parameters.
24    ///
25    /// Arguments:
26    ///
27    /// * `path`: The `path` parameter is a reference to a `Path` object, which represents the path to a
28    /// file. It is used to specify the location of the file from which the contract code will be read.
29    /// * `init`: The `init` parameter is of type `Init`. It represents the initialization parameters for
30    /// the contract being deployed. The specific structure and fields of the `Init` type would depend on
31    /// the contract being deployed.
32    /// * `overridden_params`: `overridden_params` is an optional parameter of type `TransactionParams`. It
33    /// allows you to override the default transaction parameters when deploying the contract. If you don't
34    /// want to override any parameters, you can pass `None` as the value for this parameter.
35    /// * `do_contract_compression`: Set it to true if you want your contract gets compressed before deployment.
36    ///
37    /// Returns:
38    ///
39    /// a Result object with a value of type `BaseContract<T>` if the operation is successful, or an Error
40    /// object if there is an error.
41    /// # Example
42    /// ```
43    /// use zilliqa_rs::providers::{Http, Provider};
44    /// use zilliqa_rs::contract::ScillaVariable;
45    /// use zilliqa_rs::signers::LocalWallet;
46    /// use zilliqa_rs::contract::Init;
47    /// use zilliqa_rs::contract::ContractFactory;
48    /// use std::path::PathBuf;
49    ///
50    /// #[tokio::main]
51    /// async fn main() -> anyhow::Result<()> {
52    ///     const END_POINT: &str = "http://localhost:5555";
53    ///
54    ///     let wallet = "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba".parse::<LocalWallet>()?;
55    ///
56    ///     let provider = Provider::<Http>::try_from(END_POINT)?
57    ///         .with_chain_id(222)
58    ///         .with_signer(wallet.clone());
59    ///
60    ///     let factory = ContractFactory::new(provider.into());
61    ///     let init = Init(vec![ScillaVariable::new_from_str("_scilla_version", "Uint32", "0")]);
62    ///     let contract = factory.deploy_from_file(&PathBuf::from("./tests/contracts/Timestamp.scilla"), init, None, false).await?;
63    ///     println!("addr: {:?}", contract);
64    ///     Ok(())
65    /// }
66    /// ```
67    pub async fn deploy_from_file(
68        &self,
69        path: &Path,
70        init: Init,
71        overridden_params: Option<TransactionParams>,
72        do_contract_compression: bool,
73    ) -> Result<BaseContract<T>, Error> {
74        let contract_code = {
75            let code = std::fs::read_to_string(path)?;
76            if do_contract_compression {
77                compress_contract(&code)?
78            } else {
79                code
80            }
81        };
82        self.deploy_str(contract_code, init, overridden_params).await
83    }
84
85    /// The `deploy_str` function deploys a contract with the given code and initialization parameters, and
86    /// returns a `BaseContract` object.
87    ///
88    /// Arguments:
89    ///
90    /// * `contract_code`: A string containing the code of the contract to be deployed.
91    /// * `init`: The `init` parameter is of type `Init`, which is a custom struct or enum that contains the
92    /// initialization data for the contract.
93    /// * `overridden_params`: `overridden_params` is an optional parameter of type
94    /// `Option<TransactionParams>`. It allows the caller to provide custom transaction parameters for
95    /// deploying the contract.
96    ///
97    /// Returns:
98    ///
99    /// The function `deploy_str` returns a `Result` containing either a `BaseContract<T>` or an `Error`.
100    /// # Example
101    /// ```
102    /// use zilliqa_rs::providers::{Http, Provider};
103    /// use zilliqa_rs::contract::ScillaVariable;
104    /// use zilliqa_rs::signers::LocalWallet;
105    /// use zilliqa_rs::contract::Init;
106    /// use zilliqa_rs::contract::ContractFactory;
107    /// use std::path::PathBuf;
108    ///
109    /// #[tokio::main]
110    /// async fn main() -> anyhow::Result<()> {
111    ///     const END_POINT: &str = "http://localhost:5555";
112    ///
113    ///     let wallet = "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba".parse::<LocalWallet>()?;
114    ///
115    ///     let provider = Provider::<Http>::try_from(END_POINT)?
116    ///         .with_chain_id(222)
117    ///         .with_signer(wallet.clone());
118    ///
119    ///     let factory = ContractFactory::new(provider.into());
120    ///     let init = Init(vec![ScillaVariable::new_from_str("_scilla_version", "Uint32", "0")]);
121    ///     let contract = factory.deploy_str(include_str!("../../tests/contracts/Timestamp.scilla").to_string(), init, None).await?;
122    ///     println!("addr: {:?}", contract);
123    ///     Ok(())
124    /// }
125    /// ```
126    pub async fn deploy_str(
127        &self,
128        contract_code: String,
129        init: Init,
130        overridden_params: Option<TransactionParams>,
131    ) -> Result<BaseContract<T>, Error> {
132        let tx = overridden_params
133            .map(TransactionBuilder::from)
134            .unwrap_or_default()
135            .to_address(ZilAddress::nil())
136            .amount_if_none(0_u128)
137            .code(contract_code)
138            .data(serde_json::to_string(&init)?)
139            .gas_price_if_none(parse_zil("0.002")?)
140            .gas_limit_if_none(10000u64)
141            .build();
142
143        let response: DeployContractResponse = self.client.send_transaction_without_confirm(tx).await?;
144        let transaction = Transaction::new(response.response.tran_id, self.client.provider());
145        transaction.confirm().await?;
146        Ok(BaseContract {
147            address: response.contract_address,
148            client: self.client.clone(),
149        })
150    }
151}