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 ledger::store::helpers::memory::BlockMemory,
24 prelude::{
25 PrivateKey,
26 ProgramID,
27 VM,
28 block::Transaction,
29 deployment_cost,
30 query::Query,
31 store::{ConsensusStore, helpers::memory::ConsensusMemory},
32 },
33};
34
35use aleo_std::StorageMode;
36use anyhow::{Result, bail};
37use clap::Parser;
38use colored::Colorize;
39use std::{path::PathBuf, str::FromStr};
40use zeroize::Zeroize;
41
42#[derive(Debug, Parser)]
44pub struct Deploy {
45 program_id: String,
47 #[clap(default_value = "0", long = "network")]
49 pub network: u16,
50 #[clap(long)]
52 path: Option<String>,
53 #[clap(short, long)]
55 private_key: String,
56 #[clap(short, long)]
58 query: String,
59 #[clap(long)]
61 priority_fee: u64,
62 #[clap(short, long)]
64 record: Option<String>,
65 #[clap(short, long, conflicts_with = "dry_run")]
67 broadcast: Option<String>,
68 #[clap(short, long, conflicts_with = "broadcast")]
70 dry_run: bool,
71 #[clap(long)]
73 store: Option<String>,
74 #[clap(long = "storage_path")]
77 storage_path: Option<PathBuf>,
78}
79
80impl Drop for Deploy {
81 fn drop(&mut self) {
83 self.private_key.zeroize();
84 }
85}
86
87impl Deploy {
88 pub fn parse(self) -> Result<String> {
90 if !self.dry_run && self.broadcast.is_none() && self.store.is_none() {
92 bail!("❌ Please specify one of the following actions: --broadcast, --dry-run, --store");
93 }
94
95 match self.network {
97 MainnetV0::ID => self.construct_deployment::<MainnetV0, AleoV0>(),
98 TestnetV0::ID => self.construct_deployment::<TestnetV0, AleoTestnetV0>(),
99 CanaryV0::ID => self.construct_deployment::<CanaryV0, AleoCanaryV0>(),
100 unknown_id => bail!("Unknown network ID ({unknown_id})"),
101 }
102 }
103
104 fn construct_deployment<N: Network, A: Aleo<Network = N, BaseField = N::Field>>(&self) -> Result<String> {
106 let query = Query::<N, BlockMemory<N>>::from(&self.query);
108
109 let private_key = PrivateKey::from_str(&self.private_key)?;
111
112 let program_id = ProgramID::from_str(&self.program_id)?;
114
115 let package = Developer::parse_package(program_id, &self.path)?;
117
118 println!("📦 Creating deployment transaction for '{}'...\n", &program_id.to_string().bold());
119
120 let deployment = package.deploy::<A>(None)?;
122 let deployment_id = deployment.to_deployment_id()?;
123
124 let transaction = {
126 let rng = &mut rand::thread_rng();
128
129 let storage_mode = match &self.storage_path {
131 Some(path) => StorageMode::Custom(path.clone()),
132 None => StorageMode::Production,
133 };
134 let store = ConsensusStore::<N, ConsensusMemory<N>>::open(storage_mode)?;
135
136 let vm = VM::from(store)?;
138
139 let (minimum_deployment_cost, (_, _, _)) = deployment_cost(&deployment)?;
141
142 let fee = match &self.record {
144 Some(record) => {
145 let fee_record = Developer::parse_record(&private_key, record)?;
146 let fee_authorization = vm.authorize_fee_private(
147 &private_key,
148 fee_record,
149 minimum_deployment_cost,
150 self.priority_fee,
151 deployment_id,
152 rng,
153 )?;
154 vm.execute_fee_authorization(fee_authorization, Some(&query), rng)?
155 }
156 None => {
157 let fee_authorization = vm.authorize_fee_public(
158 &private_key,
159 minimum_deployment_cost,
160 self.priority_fee,
161 deployment_id,
162 rng,
163 )?;
164 vm.execute_fee_authorization(fee_authorization, Some(&query), rng)?
165 }
166 };
167 let owner = ProgramOwner::new(&private_key, deployment_id, rng)?;
169
170 Transaction::from_deployment(owner, deployment, fee)?
172 };
173 println!("✅ Created deployment transaction for '{}'", program_id.to_string().bold());
174
175 Developer::handle_transaction(&self.broadcast, self.dry_run, &self.store, transaction, program_id.to_string())
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use crate::commands::{CLI, Command};
184
185 #[test]
186 fn clap_snarkos_deploy() {
187 let arg_vec = vec![
188 "snarkos",
189 "developer",
190 "deploy",
191 "--private-key",
192 "PRIVATE_KEY",
193 "--query",
194 "QUERY",
195 "--priority-fee",
196 "77",
197 "--record",
198 "RECORD",
199 "hello.aleo",
200 ];
201 let cli = CLI::parse_from(arg_vec);
202
203 if let Command::Developer(Developer::Deploy(deploy)) = cli.command {
204 assert_eq!(deploy.network, 0);
205 assert_eq!(deploy.program_id, "hello.aleo");
206 assert_eq!(deploy.private_key, "PRIVATE_KEY");
207 assert_eq!(deploy.query, "QUERY");
208 assert_eq!(deploy.priority_fee, 77);
209 assert_eq!(deploy.record, Some("RECORD".to_string()));
210 } else {
211 panic!("Unexpected result of clap parsing!");
212 }
213 }
214}