1pub mod deploy;
2pub mod facilitator;
3pub mod project;
4pub mod test;
5pub mod wallet;
6
7use anyhow::Result;
8use clap::Parser;
9use colored::Colorize;
10
11pub use facilitator::Facilitator;
12pub use project::Project;
13pub use wallet::Wallet;
14
15#[derive(Parser)]
16pub enum WalletCommands {
17 #[command(name = "create")]
18 Create {
19 #[arg(short, long, default_value = "testnet")]
20 network: String,
21 },
22 #[command(name = "import")]
23 Import {
24 #[arg(short, long)]
25 private_key: String,
26 #[arg(short, long, default_value = "testnet")]
27 network: String,
28 },
29}
30
31#[derive(Parser)]
32pub enum FacilitatorCommands {
33 #[command(name = "start")]
34 Start {
35 #[arg(short, long, default_value = "3001")]
36 port: u16,
37 #[arg(long)]
38 wallet: Option<String>,
39 #[arg(long)]
40 private_key: Option<String>,
41 #[arg(short, long, default_value = "testnet")]
42 network: String,
43 },
44 #[command(name = "stop")]
45 Stop,
46}
47
48#[derive(Parser)]
49pub enum TestCommands {
50 #[command(name = "payment")]
51 Payment {
52 #[arg(short, long)]
53 api: String,
54 #[arg(short, long, default_value = "1000")]
55 amount: u64,
56 },
57}
58
59pub async fn init(name: String, chain: String, framework: String) -> Result<()> {
60 println!(
61 "{}",
62 format!("Initializing x402 project: {}", name.cyan()).bold()
63 );
64
65 let project = Project::new(name.clone(), chain, framework);
66
67 println!("{}", " Creating project structure...".dimmed());
68 project.create_directories()?;
69
70 println!("{}", " Creating configuration files...".dimmed());
71 project.create_config_files()?;
72
73 println!("{}", " Installing dependencies...".dimmed());
74 project.install_dependencies()?;
75
76 project.generate_readme()?;
77
78 println!(
79 "{}",
80 format!("✓ Project initialized: {}", name.green()).bold()
81 );
82
83 println!(
84 "{}",
85 format!(" Project location: {}/", name.cyan()).dimmed()
86 );
87
88 Ok(())
89}
90
91pub async fn handle_wallet(command: WalletCommands) -> Result<()> {
92 match command {
93 WalletCommands::Create { network } => {
94 println!("{}", "Creating wallet...".cyan());
95
96 let wallet = Wallet::create(&network).await?;
97
98 wallet.save_to_file()?;
99
100 wallet.fund_from_faucet().await?;
101
102 println!(
103 "{}",
104 format!(" Wallet Address: {}", wallet.address.cyan()).dimmed()
105 );
106
107 Ok(())
108 }
109 WalletCommands::Import { private_key, network } => {
110 println!("{}", "Importing wallet...".cyan());
111
112 let wallet = Wallet::import(&private_key, &network)?;
113
114 wallet.save_to_file()?;
115
116 println!(
117 "{}",
118 format!(" Wallet Address: {}", wallet.address.cyan()).dimmed()
119 );
120
121 Ok(())
122 }
123 }
124}
125
126pub async fn handle_facilitator(command: FacilitatorCommands) -> Result<()> {
127 match command {
128 FacilitatorCommands::Start { port, wallet, private_key, network } => {
129 let wallet = if let Some(private_key) = private_key {
130 Wallet::import(&private_key, &network)?
131 } else if let Some(wallet_address) = wallet {
132 Wallet::load_from_address(&wallet_address)?
133 } else {
134 Wallet::find_default()?
135 };
136
137 let _facilitator = Facilitator::start(port, wallet)?;
138
139 println!("{}", " Start facilitator in background...".dimmed());
140 println!(
141 "{}",
142 " Run `x402 facilitator stop` to stop".yellow().dimmed()
143 );
144
145 Ok(())
146 }
147 FacilitatorCommands::Stop => {
148 Facilitator::stop()?;
149 println!("{}", "✓ Facilitator stopped".green().bold());
150 Ok(())
151 }
152 }
153}
154
155pub async fn handle_test(command: TestCommands) -> Result<()> {
156 match command {
157 TestCommands::Payment { api, amount } => {
158 println!("{}", "Testing payment flow...".cyan());
159 println!("{}", format!(" API URL: {}", api.cyan()).dimmed());
160 println!("{}", format!(" Amount: {}", amount));
161
162 test::test_payment_flow(&api, amount).await?;
163
164 Ok(())
165 }
166 }
167}
168
169pub async fn deploy(provider: String) -> Result<()> {
170 println!("{}", format!("Deploying to {}", provider.cyan()).bold());
171
172 deploy::deploy(&provider).await?;
173
174 Ok(())
175}