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")]
76 storage_path: Option<PathBuf>,
77}
78
79impl Drop for Deploy {
80 fn drop(&mut self) {
82 self.private_key.zeroize();
83 }
84}
85
86impl Deploy {
87 pub fn parse(self) -> Result<String> {
89 if !self.dry_run && self.broadcast.is_none() && self.store.is_none() {
91 bail!("❌ Please specify one of the following actions: --broadcast, --dry-run, --store");
92 }
93
94 match self.network {
96 MainnetV0::ID => self.construct_deployment::<MainnetV0, AleoV0>(),
97 TestnetV0::ID => self.construct_deployment::<TestnetV0, AleoTestnetV0>(),
98 CanaryV0::ID => self.construct_deployment::<CanaryV0, AleoCanaryV0>(),
99 unknown_id => bail!("Unknown network ID ({unknown_id})"),
100 }
101 }
102
103 fn construct_deployment<N: Network, A: Aleo<Network = N, BaseField = N::Field>>(&self) -> Result<String> {
105 let query = Query::from(&self.query);
107
108 let private_key = PrivateKey::from_str(&self.private_key)?;
110
111 let program_id = ProgramID::from_str(&self.program_id)?;
113
114 let package = Developer::parse_package(program_id, &self.path)?;
116
117 println!("📦 Creating deployment transaction for '{}'...\n", &program_id.to_string().bold());
118
119 let deployment = package.deploy::<A>(None)?;
121 let deployment_id = deployment.to_deployment_id()?;
122
123 let transaction = {
125 let rng = &mut rand::thread_rng();
127
128 let storage_mode = match &self.storage_path {
130 Some(path) => StorageMode::Custom(path.clone()),
131 None => StorageMode::Production,
132 };
133 let store = ConsensusStore::<N, ConsensusMemory<N>>::open(storage_mode)?;
134
135 let vm = VM::from(store)?;
137
138 let (minimum_deployment_cost, (_, _, _)) = deployment_cost(&deployment)?;
140
141 let fee = match &self.record {
143 Some(record) => {
144 let fee_record = Developer::parse_record(&private_key, record)?;
145 let fee_authorization = vm.authorize_fee_private(
146 &private_key,
147 fee_record,
148 minimum_deployment_cost,
149 self.priority_fee,
150 deployment_id,
151 rng,
152 )?;
153 vm.execute_fee_authorization(fee_authorization, Some(query), rng)?
154 }
155 None => {
156 let fee_authorization = vm.authorize_fee_public(
157 &private_key,
158 minimum_deployment_cost,
159 self.priority_fee,
160 deployment_id,
161 rng,
162 )?;
163 vm.execute_fee_authorization(fee_authorization, Some(query), rng)?
164 }
165 };
166 let owner = ProgramOwner::new(&private_key, deployment_id, rng)?;
168
169 Transaction::from_deployment(owner, deployment, fee)?
171 };
172 println!("✅ Created deployment transaction for '{}'", program_id.to_string().bold());
173
174 Developer::handle_transaction(&self.broadcast, self.dry_run, &self.store, transaction, program_id.to_string())
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use crate::commands::{CLI, Command};
183
184 #[test]
185 fn clap_snarkos_deploy() {
186 let arg_vec = vec![
187 "snarkos",
188 "developer",
189 "deploy",
190 "--private-key",
191 "PRIVATE_KEY",
192 "--query",
193 "QUERY",
194 "--priority-fee",
195 "77",
196 "--record",
197 "RECORD",
198 "hello.aleo",
199 ];
200 let cli = CLI::parse_from(arg_vec);
201
202 if let Command::Developer(Developer::Deploy(deploy)) = cli.command {
203 assert_eq!(deploy.network, 0);
204 assert_eq!(deploy.program_id, "hello.aleo");
205 assert_eq!(deploy.private_key, "PRIVATE_KEY");
206 assert_eq!(deploy.query, "QUERY");
207 assert_eq!(deploy.priority_fee, 77);
208 assert_eq!(deploy.record, Some("RECORD".to_string()));
209 } else {
210 panic!("Unexpected result of clap parsing!");
211 }
212 }
213}