1
use clap::{command, ArgGroup, Args, Parser, Subcommand};
2

            
3
#[derive(Parser, Debug)]
4
#[command(version)]
5
#[command(group(
6
    // Ensures mutual exclusivity of config, or keypair and rpc_url
7
    ArgGroup::new("config_group")
8
        .required(false)
9
        .args(&["config"])
10
        .conflicts_with("rpc_url")
11
        .conflicts_with("keypair")
12
        .multiple(false)
13
))]
14
pub struct BonsolCli {
15
    #[arg(
16
        help = "The path to a Solana CLI config [Default: '~/.config/solana/cli/config.yml']",
17
        short = 'c',
18
        long
19
    )]
20
    pub config: Option<String>,
21

            
22
    #[arg(
23
        help = "The path to a Solana keypair file [Default: '~/.config/solana/id.json']",
24
        short = 'k',
25
        long,
26
        requires = "rpc_url"
27
    )]
28
    pub keypair: Option<String>,
29

            
30
    #[arg(
31
        help = "The Solana cluster the Solana CLI will make requests to",
32
        short = 'u',
33
        long,
34
        requires = "keypair"
35
    )]
36
    pub rpc_url: Option<String>,
37

            
38
    #[command(subcommand)]
39
    pub command: Command,
40
}
41

            
42
#[derive(Debug, Clone, Args)]
43
pub struct S3UploadArgs {
44
    #[arg(
45
        help = "Specify the S3 bucket name",
46
        long,
47
        required = true,
48
        value_parser = |s: &str| {
49
            if s.trim().is_empty() {
50
                anyhow::bail!("expected a non-empty string representation of an S3 bucket name")
51
            }
52
            Ok(s.to_string())
53
        }
54
    )]
55
    pub bucket: String,
56

            
57
    #[arg(
58
        help = "Specify the AWS access key ID",
59
        long,
60
        required = true,
61
        env = "AWS_ACCESS_KEY_ID"
62
    )]
63
    pub access_key: String,
64

            
65
    #[arg(
66
        help = "Specify the AWS secret access key",
67
        long,
68
        required = true,
69
        env = "AWS_SECRET_ACCESS_KEY"
70
    )]
71
    pub secret_key: String,
72

            
73
    #[arg(
74
        help = "Specify the AWS region",
75
        long,
76
        required = true,
77
        env = "AWS_REGION"
78
    )]
79
    pub region: String,
80

            
81
    #[arg(
82
        help = "Specify the AWS S3 compatibility endpoint",
83
        long,
84
        required = false,
85
        env = "AWS_S3_ENDPOINT"
86
    )]
87
    pub endpoint: Option<String>,
88

            
89
    #[command(flatten)]
90
    pub shared_args: SharedDeployArgs,
91
}
92

            
93
#[derive(Debug, Clone, Args)]
94
pub struct UrlUploadArgs {
95
    #[arg(help = "Specify a URL endpoint to deploy to", long, required = true)]
96
    pub url: String,
97

            
98
    #[command(flatten)]
99
    pub shared_args: SharedDeployArgs,
100
}
101

            
102
#[derive(Debug, Clone, Subcommand)]
103
pub enum DeployArgs {
104
    #[command(about = "Deploy a program using an AWS S3 bucket")]
105
    S3(S3UploadArgs),
106

            
107
    #[command(about = "Deploy a program manually with a URL")]
108
    Url(UrlUploadArgs),
109
}
110

            
111
impl DeployArgs {
112
    pub fn shared_args(&self) -> SharedDeployArgs {
113
        match self {
114
            Self::S3(s3) => s3.shared_args.clone(),
115
            Self::Url(url) => url.shared_args.clone(),
116
        }
117
    }
118
}
119

            
120
#[derive(Debug, Clone, Args)]
121
pub struct SharedDeployArgs {
122
    #[arg(
123
        help = "The path to the program's manifest file (manifest.json)",
124
        short = 'm',
125
        long
126
    )]
127
    pub manifest_path: String,
128

            
129
    #[arg(
130
        help = "Whether to automatically confirm deployment",
131
        short = 'y',
132
        long
133
    )]
134
    pub auto_confirm: bool,
135
}
136

            
137
#[derive(Subcommand, Debug)]
138
pub enum Command {
139
    #[command(
140
        about = "Deploy a program with various storage options, such as S3, or manually with a URL"
141
    )]
142
    Deploy {
143
        #[clap(subcommand)]
144
        deploy_args: DeployArgs,
145
    },
146

            
147
    #[command(about = "Build a ZK program")]
148
    Build {
149
        #[arg(
150
            help = "The path to a ZK program folder containing a Cargo.toml",
151
            short = 'z',
152
            long
153
        )]
154
        zk_program_path: String,
155
    },
156

            
157
    #[command(about = "Estimate the execution cost of a ZK RISC0 program")]
158
    Estimate {
159
        #[arg(
160
            help = "The path to the program's manifest file (manifest.json)",
161
            short = 'm',
162
            long
163
        )]
164
        manifest_path: String,
165

            
166
        #[arg(help = "The path to the program input file", short = 'i', long)]
167
        input_file: Option<String>,
168

            
169
        #[arg(
170
            help = "Set the maximum number of cycles [default: 16777216u64]",
171
            short = 'c',
172
            long
173
        )]
174
        max_cycles: Option<u64>,
175
    },
176

            
177
    Execute {
178
        #[arg(short = 'f', long)]
179
        execution_request_file: Option<String>,
180

            
181
        // overridable settings
182
        #[arg(short = 'p', long)]
183
        program_id: Option<String>,
184

            
185
        #[arg(short = 'e', long)]
186
        execution_id: Option<String>,
187

            
188
        #[arg(short = 'x', long)]
189
        expiry: Option<u64>,
190

            
191
        #[arg(short = 'm', long)]
192
        tip: Option<u64>,
193

            
194
        #[arg(short = 'i', long, help = "override inputs in execution request file")]
195
        input_file: Option<String>,
196

            
197
        /// wait for execution to be proven
198
        #[arg(short = 'w', long, help = "wait for execution to be proven")]
199
        wait: bool,
200

            
201
        /// timeout in seconds
202
        #[arg(short = 't', long, help = "timeout in seconds")]
203
        timeout: Option<u64>,
204
    },
205

            
206
    Prove {
207
        #[arg(short = 'm', long)]
208
        manifest_path: Option<String>,
209

            
210
        #[arg(short = 'p', long)]
211
        program_id: Option<String>,
212

            
213
        #[arg(short = 'i')]
214
        input_file: Option<String>,
215

            
216
        #[arg(short = 'e', long)]
217
        execution_id: String,
218

            
219
        #[arg(short = 'o')]
220
        output_location: Option<String>,
221
    },
222

            
223
    #[command(about = "Initialize a new project")]
224
    Init {
225
        #[arg(short = 'd', long)]
226
        dir: Option<String>,
227

            
228
        #[arg(short = 'n', long)]
229
        project_name: String,
230
    },
231
}