snarkos_cli/commands/developer/
deploy.rs1use super::Developer;
17use snarkvm::{
18 circuit::{Aleo, AleoCanaryV0, AleoTestnetV0, AleoV0},
19 console::{
20 network::{CanaryV0, MainnetV0, Network, TestnetV0},
21 program::ProgramOwner,
22 },
23 prelude::{
24 PrivateKey,
25 ProgramID,
26 VM,
27 block::Transaction,
28 deployment_cost,
29 query::Query,
30 store::{ConsensusStore, helpers::memory::ConsensusMemory},
31 },
32};
33
34use aleo_std::StorageMode;
35use anyhow::{Result, bail};
36use clap::Parser;
37use colored::Colorize;
38use std::{path::PathBuf, str::FromStr};
39use zeroize::Zeroize;
40
41#[derive(Debug, Parser)]
43pub struct Deploy {
44 program_id: String,
46 #[clap(default_value = "0", long = "network")]
48 pub network: u16,
49 #[clap(long)]
51 path: Option<String>,
52 #[clap(short, long)]
54 private_key: String,
55 #[clap(short, long)]
57 query: String,
58 #[clap(long)]
60 priority_fee: u64,
61 #[clap(short, long)]
63 record: Option<String>,
64 #[clap(short, long, conflicts_with = "dry_run")]
66 broadcast: Option<String>,
67 #[clap(short, long, conflicts_with = "broadcast")]
69 dry_run: bool,
70 #[clap(long)]
72 store: Option<String>,
73 #[clap(long = "storage_path")]
75 storage_path: Option<PathBuf>,
76}
77
78impl Drop for Deploy {
79 fn drop(&mut self) {
81 self.private_key.zeroize();
82 }
83}
84
85impl Deploy {
86 pub fn parse(self) -> Result<String> {
88 if !self.dry_run && self.broadcast.is_none() && self.store.is_none() {
90 bail!("❌ Please specify one of the following actions: --broadcast, --dry-run, --store");
91 }
92
93 match self.network {
95 MainnetV0::ID => self.construct_deployment::<MainnetV0, AleoV0>(),
96 TestnetV0::ID => self.construct_deployment::<TestnetV0, AleoTestnetV0>(),
97 CanaryV0::ID => self.construct_deployment::<CanaryV0, AleoCanaryV0>(),
98 unknown_id => bail!("Unknown network ID ({unknown_id})"),
99 }
100 }
101
102 fn construct_deployment<N: Network, A: Aleo<Network = N, BaseField = N::Field>>(&self) -> Result<String> {
104 let query = Query::from(&self.query);
106
107 let private_key = PrivateKey::from_str(&self.private_key)?;
109
110 let program_id = ProgramID::from_str(&self.program_id)?;
112
113 let package = Developer::parse_package(program_id, &self.path)?;
115
116 println!("📦 Creating deployment transaction for '{}'...\n", &program_id.to_string().bold());
117
118 let deployment = package.deploy::<A>(None)?;
120 let deployment_id = deployment.to_deployment_id()?;
121
122 let transaction = {
124 let rng = &mut rand::thread_rng();
126
127 let storage_mode = match &self.storage_path {
129 Some(path) => StorageMode::Custom(path.clone()),
130 None => StorageMode::Production,
131 };
132 let store = ConsensusStore::<N, ConsensusMemory<N>>::open(storage_mode)?;
133
134 let vm = VM::from(store)?;
136
137 let (minimum_deployment_cost, (_, _, _)) = deployment_cost(&deployment)?;
139
140 let fee = match &self.record {
142 Some(record) => {
143 let fee_record = Developer::parse_record(&private_key, record)?;
144 let fee_authorization = vm.authorize_fee_private(
145 &private_key,
146 fee_record,
147 minimum_deployment_cost,
148 self.priority_fee,
149 deployment_id,
150 rng,
151 )?;
152 vm.execute_fee_authorization(fee_authorization, Some(query), rng)?
153 }
154 None => {
155 let fee_authorization = vm.authorize_fee_public(
156 &private_key,
157 minimum_deployment_cost,
158 self.priority_fee,
159 deployment_id,
160 rng,
161 )?;
162 vm.execute_fee_authorization(fee_authorization, Some(query), rng)?
163 }
164 };
165 let owner = ProgramOwner::new(&private_key, deployment_id, rng)?;
167
168 Transaction::from_deployment(owner, deployment, fee)?
170 };
171 println!("✅ Created deployment transaction for '{}'", program_id.to_string().bold());
172
173 Developer::handle_transaction(&self.broadcast, self.dry_run, &self.store, transaction, program_id.to_string())
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use crate::commands::{CLI, Command};
182
183 #[test]
184 fn clap_snarkos_deploy() {
185 let arg_vec = vec![
186 "snarkos",
187 "developer",
188 "deploy",
189 "--private-key",
190 "PRIVATE_KEY",
191 "--query",
192 "QUERY",
193 "--priority-fee",
194 "77",
195 "--record",
196 "RECORD",
197 "hello.aleo",
198 ];
199 let cli = CLI::parse_from(arg_vec);
200
201 if let Command::Developer(Developer::Deploy(deploy)) = cli.command {
202 assert_eq!(deploy.network, 0);
203 assert_eq!(deploy.program_id, "hello.aleo");
204 assert_eq!(deploy.private_key, "PRIVATE_KEY");
205 assert_eq!(deploy.query, "QUERY");
206 assert_eq!(deploy.priority_fee, 77);
207 assert_eq!(deploy.record, Some("RECORD".to_string()));
208 } else {
209 panic!("Unexpected result of clap parsing!");
210 }
211 }
212}