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}