1use super::*;
18
19impl<N: Network> Rest<N> {
20 pub fn routes(&self) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone {
22 let deploy = warp::post()
24 .and(warp::path!("testnet3" / "deploy"))
25 .and(warp::body::content_length_limit(16 * 1024 * 1024))
26 .and(warp::body::json())
27 .and(with(self.record_finder.clone()))
28 .and(with(self.private_key_ciphertext.clone()))
29 .and(with(self.api_client.clone()))
30 .and_then(Self::deploy_program);
31
32 let execute = warp::post()
34 .and(warp::path!("testnet3" / "execute"))
35 .and(warp::body::content_length_limit(16 * 1024 * 1024))
36 .and(warp::body::json())
37 .and(with(self.record_finder.clone()))
38 .and(with(self.private_key_ciphertext.clone()))
39 .and(with(self.api_client.clone()))
40 .and_then(Self::execute_program);
41
42 let transfer = warp::post()
44 .and(warp::path!("testnet3" / "transfer"))
45 .and(warp::body::content_length_limit(16 * 1024 * 1024))
46 .and(warp::body::json())
47 .and(with(self.record_finder.clone()))
48 .and(with(self.private_key_ciphertext.clone()))
49 .and(with(self.api_client.clone()))
50 .and_then(Self::transfer);
51
52 let health = warp::get().and(warp::path!("health")).map(reply::reply);
54
55 deploy.or(execute).or(transfer).or(health)
56 }
57}
58
59impl<N: Network> Rest<N> {
60 fn get_private_key(
62 private_key_ciphertext: Option<Ciphertext<N>>,
63 private_key: Option<PrivateKey<N>>,
64 password: Option<String>,
65 ) -> Result<PrivateKey<N>, Rejection> {
66 if let Some(private_key) = private_key {
67 Ok(private_key)
68 } else if let Some(password) = private_key_ciphertext.as_ref().and(password) {
69 let private_key_ciphertext = private_key_ciphertext.as_ref().unwrap();
70 Encryptor::decrypt_private_key_with_secret(private_key_ciphertext, &password).or_reject()
71 } else {
72 if private_key_ciphertext.is_none() {
73 return Err(reject::custom(RestError::Request(
74 "No private key was provided, and no encrypted keys were found in the server's configuration."
75 .to_string(),
76 )));
77 }
78 Err(reject::custom(RestError::Request("No private key or decryption passwords were provided.".to_string())))
79 }
80 }
81
82 fn get_api_client(api_client: AleoAPIClient<N>, peer_url: &Option<String>) -> Result<AleoAPIClient<N>, Rejection> {
84 if let Some(peer_url) = peer_url {
85 AleoAPIClient::new(peer_url, "testnet3").or_reject()
86 } else {
87 Ok(api_client)
88 }
89 }
90
91 async fn deploy_program(
93 request: DeployRequest<N>,
94 record_finder: RecordFinder<N>,
95 private_key_ciphertext: Option<Ciphertext<N>>,
96 api_client: AleoAPIClient<N>,
97 ) -> Result<impl Reply, Rejection> {
98 if request.fee == 0 {
100 return Err(reject::custom(RestError::Request(
101 "Fee must be greater than zero in order to deploy a program to the Aleo Network".to_string(),
102 )));
103 }
104 let api_client = Self::get_api_client(api_client, &request.peer_url)?;
106 let private_key = Self::get_private_key(private_key_ciphertext, request.private_key, request.password.clone())?;
107 let mut program_manager = ProgramManager::new(Some(private_key), None, Some(api_client), None).or_reject()?;
108 program_manager.add_program(&request.program).or_reject()?;
109
110 let fee_record = if request.fee_record.is_none() {
112 spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?
113 } else {
114 request.fee_record.unwrap()
115 };
116
117 let transaction_id =
119 spawn_blocking!(program_manager.deploy_program(request.program.id(), request.fee, fee_record, None))?;
120
121 Ok(reply::json(&transaction_id))
122 }
123
124 async fn execute_program(
126 mut request: ExecuteRequest<N>,
127 record_finder: RecordFinder<N>,
128 private_key_ciphertext: Option<Ciphertext<N>>,
129 api_client: AleoAPIClient<N>,
130 ) -> Result<impl Reply, Rejection> {
131 if request.fee == 0 {
132 return Err(reject::custom(RestError::Request(
133 "Fee must be greater than zero in order to execute a program on the Aleo Network".to_string(),
134 )));
135 }
136 let api_client = Self::get_api_client(api_client, &request.peer_url)?;
138 let private_key = Self::get_private_key(private_key_ciphertext, request.private_key, request.password.clone())?;
139 let mut program_manager = ProgramManager::new(Some(private_key), None, Some(api_client), None).or_reject()?;
140
141 let fee_record = if request.fee_record.is_none() {
143 spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?
144 } else {
145 request.fee_record.take().unwrap()
146 };
147
148 let transaction_id = spawn_blocking!(program_manager.execute_program(
150 request.program_id,
151 request.program_function,
152 request.inputs.iter(),
153 request.fee,
154 fee_record,
155 None,
156 ))?;
157
158 Ok(reply::json(&transaction_id))
159 }
160
161 async fn transfer(
163 request: TransferRequest<N>,
164 record_finder: RecordFinder<N>,
165 private_key_ciphertext: Option<Ciphertext<N>>,
166 api_client: AleoAPIClient<N>,
167 ) -> Result<impl Reply, Rejection> {
168 if request.fee == 0 {
170 return Err(reject::custom(RestError::Request(
171 "Fee must be greater than zero in order to transfer funds on the Aleo Network".to_string(),
172 )));
173 }
174 let api_client = Self::get_api_client(api_client, &request.peer_url)?;
175 let private_key = Self::get_private_key(private_key_ciphertext, request.private_key, request.password.clone())?;
176 let program_manager = ProgramManager::new(Some(private_key), None, Some(api_client), None).or_reject()?;
177
178 let specified_transfer_type = request.transfer_type.as_str();
179 info!("Transfer type specified: {specified_transfer_type}");
180 let transfer_type = match specified_transfer_type {
181 "private" => { TransferType::Private },
182 "public" => { TransferType::Public },
183 "private_to_public" => { TransferType::PrivateToPublic },
184 "public_to_private" => { TransferType::PublicToPrivate },
185 _ => Err(anyhow!("Invalid transfer type specified, type must be one of the following: private, public, private-to-public, public-to-private")).or_reject()?,
186 };
187
188 let (amount_record, fee_record) =
189 match transfer_type {
190 TransferType::Public => {
191 if let Some(fee_record) = request.fee_record {
192 (None, fee_record)
193 } else {
194 (None, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?)
195 }
196 }
197 TransferType::PublicToPrivate => {
198 if let Some(fee_record) = request.fee_record {
199 (None, fee_record)
200 } else {
201 (None, spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?)
202 }
203 }
204 _ => {
205 match (request.amount_record, request.fee_record) {
206 (Some(amount_record), Some(fee_record)) => (Some(amount_record), fee_record),
207 (Some(amount_record), None) => {
208 (
210 Some(amount_record),
211 spawn_blocking!(record_finder.find_one_record(&private_key, request.fee))?,
212 )
213 }
214 (None, Some(fee_record)) => (
215 Some(spawn_blocking!(record_finder.find_one_record(&private_key, request.amount))?),
216 fee_record,
217 ),
218 (None, None) => {
219 let (amount_record, fee_record) = spawn_blocking!(
220 record_finder.find_amount_and_fee_records(request.amount, request.fee, &private_key)
221 )?;
222 (Some(amount_record), fee_record)
223 }
224 }
225 }
226 };
227
228 let transaction_id = spawn_blocking!(program_manager.transfer(
230 request.amount,
231 request.fee,
232 request.recipient,
233 transfer_type,
234 None,
235 amount_record,
236 fee_record
237 ))?;
238 Ok(reply::json(&transaction_id))
239 }
240}