1use std::{path::PathBuf, str::FromStr};
2
3use anyhow::anyhow;
4use clap::{Args, Parser};
5use clap_stdin::MaybeStdin;
6use serde::{Deserialize, Serialize};
7use snarkvm::{
8 ledger::{Deployment, Transition},
9 prelude::{PrivateKey, ProgramOwner, Request},
10 synthesizer::Authorization,
11 utilities::DeserializeExt,
12};
13
14use crate::{Key, Network};
15
16#[derive(Clone, Debug, Parser)]
18pub struct AuthArgs<N: Network> {
19 #[clap(short, long)]
21 pub auth: Option<ProxyAuthorization<N>>,
22 #[clap(short, long)]
24 pub fee_auth: Option<ProxyAuthorization<N>>,
25 #[clap(short, long)]
27 pub owner: Option<ProgramOwner<N>>,
28 #[clap(short, long)]
30 pub deployment: Option<Deployment<N>>,
31 json: Option<MaybeStdin<AuthBlob<N>>>,
37}
38
39impl<N: Network> AuthArgs<N> {
40 pub fn pick(self) -> anyhow::Result<AuthBlob<N>> {
41 self.json
42 .map(MaybeStdin::into_inner)
43 .or_else(|| match (self.auth, self.owner, self.deployment) {
44 (Some(auth), None, None) => Some(AuthBlob::Program {
45 auth,
46 fee_auth: self.fee_auth,
47 }),
48 (None, Some(owner), Some(deployment)) => Some(AuthBlob::Deploy {
49 owner,
50 deployment,
51 fee_auth: self.fee_auth,
52 }),
53 _ => None,
54 })
55 .ok_or(anyhow!("No authorization provided"))
56 }
57}
58
59#[derive(Clone, Debug, Serialize)]
68#[serde(untagged)]
69pub enum AuthBlob<N: Network> {
70 Program {
71 auth: ProxyAuthorization<N>,
73 fee_auth: Option<ProxyAuthorization<N>>,
75 },
76 Deploy {
77 owner: ProgramOwner<N>,
79 deployment: Deployment<N>,
81 #[serde(skip_serializing_if = "Option::is_none")]
83 fee_auth: Option<ProxyAuthorization<N>>,
84 },
85}
86
87impl<'de, N: Network> Deserialize<'de> for AuthBlob<N> {
88 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89 where
90 D: serde::Deserializer<'de>,
91 {
92 let mut value = serde_json::Value::deserialize(deserializer)?;
93 let fee_auth = value
94 .get("fee_auth")
95 .is_some()
96 .then(|| DeserializeExt::take_from_value::<D>(&mut value, "fee_auth"))
97 .transpose()?;
98
99 if value.get("auth").is_some() {
100 Ok(Self::Program {
101 fee_auth,
102 auth: DeserializeExt::take_from_value::<D>(&mut value, "auth")?,
103 })
104 } else {
105 Ok(Self::Deploy {
106 fee_auth,
107 owner: DeserializeExt::take_from_value::<D>(&mut value, "owner")?,
108 deployment: DeserializeExt::take_from_value::<D>(&mut value, "deployment")?,
109 })
110 }
111 }
112}
113
114impl<N: Network> FromStr for AuthBlob<N> {
115 type Err = serde_json::Error;
116
117 fn from_str(s: &str) -> Result<Self, Self::Err> {
118 serde_json::from_str(s)
119 }
120}
121
122#[derive(Clone, Debug, Serialize)]
128pub struct ProxyAuthorization<N: Network> {
129 pub requests: Vec<Request<N>>,
130 pub transitions: Vec<Transition<N>>,
131}
132
133impl<'de, N: Network> Deserialize<'de> for ProxyAuthorization<N> {
134 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
135 where
136 D: serde::Deserializer<'de>,
137 {
138 let mut value = serde_json::Value::deserialize(deserializer)?;
139 Ok(Self {
140 requests: DeserializeExt::take_from_value::<D>(&mut value, "requests")?,
141 transitions: DeserializeExt::take_from_value::<D>(&mut value, "transitions")?,
142 })
143 }
144}
145
146impl<N: Network> FromStr for ProxyAuthorization<N> {
147 type Err = serde_json::Error;
148
149 fn from_str(s: &str) -> Result<Self, Self::Err> {
150 serde_json::from_str(s)
151 }
152}
153
154impl<N: Network> From<ProxyAuthorization<N>> for Authorization<N> {
155 fn from(auth: ProxyAuthorization<N>) -> Self {
156 let new_auth = Authorization::try_from((vec![], vec![])).unwrap();
157 for req in auth.requests {
158 new_auth.push(req);
159 }
160 for transition in auth.transitions {
161 let _ = new_auth.insert_transition(transition);
162 }
163
164 new_auth
165 }
166}
167
168impl<N: Network> From<Authorization<N>> for ProxyAuthorization<N> {
169 fn from(auth: Authorization<N>) -> Self {
170 let mut requests = vec![];
171 let mut transitions = vec![];
172
173 for req in auth.to_vec_deque() {
174 requests.push(req.clone());
175 }
176 for transition in auth.transitions().values() {
177 transitions.push(transition.clone());
178 }
179
180 Self {
181 requests,
182 transitions,
183 }
184 }
185}
186
187#[derive(Debug, Args, Clone)]
190#[group(multiple = false)]
191pub struct FeeKey<N: Network> {
192 #[clap(long = "fee-private-key")]
194 pub fee_private_key: Option<PrivateKey<N>>,
195 #[clap(long = "fee-private-key-file")]
197 pub fee_private_key_file: Option<PathBuf>,
198}
199
200impl<N: Network> FeeKey<N> {
201 pub fn get(self) -> Option<PrivateKey<N>> {
202 match (self.fee_private_key, self.fee_private_key_file) {
203 (Some(key), None) => Some(key),
204 (None, Some(file)) => {
205 let raw = std::fs::read_to_string(file).ok()?.trim().to_string();
206 PrivateKey::from_str(&raw).ok()
207 }
208 _ => None,
209 }
210 }
211
212 pub fn as_key(self) -> Option<Key<N>> {
213 Some(Key {
214 private_key: Some(self.get()?),
217 private_key_file: None,
218 })
219 }
220}