1use anyhow::{Context, Result};
2
3use crate::api::ApiClient;
4use crate::config::NetworkConfig;
5
6pub fn resolve_wallet_key(api_key: Option<&str>) -> Result<String> {
8 if let Some(key) = api_key {
9 return Ok(key.to_string());
10 }
11 std::env::var("OUTLAYER_WALLET_KEY")
12 .context("Wallet API key required. Use --api-key or set OUTLAYER_WALLET_KEY env var")
13}
14
15pub async fn create(
17 network: &NetworkConfig,
18 api_key: Option<&str>,
19 token: &str,
20 amount: &str,
21 memo: Option<&str>,
22 expires_in: Option<u64>,
23) -> Result<()> {
24 let key = resolve_wallet_key(api_key)?;
25 let api = ApiClient::new(network);
26
27 eprintln!("Creating payment check...");
28
29 let resp = api
30 .create_payment_check(&key, token, amount, memo, expires_in)
31 .await?;
32
33 println!("check_id: {}", resp.check_id);
34 println!("check_key: {}", resp.check_key);
35 println!("token: {}", resp.token);
36 println!("amount: {}", resp.amount);
37 if let Some(memo) = &resp.memo {
38 println!("memo: {}", memo);
39 }
40 println!("created: {}", resp.created_at);
41 if let Some(expires) = &resp.expires_at {
42 println!("expires: {}", expires);
43 }
44
45 eprintln!("\nSave the check_key — it is shown only once. Send it to the recipient.");
46
47 Ok(())
48}
49
50pub async fn batch_create(
52 network: &NetworkConfig,
53 api_key: Option<&str>,
54 file: &str,
55) -> Result<()> {
56 let key = resolve_wallet_key(api_key)?;
57 let api = ApiClient::new(network);
58
59 let data = std::fs::read_to_string(file)
60 .with_context(|| format!("Failed to read file: {}", file))?;
61 let checks: Vec<serde_json::Value> =
62 serde_json::from_str(&data).context("Invalid JSON in checks file. Expected array of {token, amount, memo?, expires_in?}")?;
63
64 if checks.is_empty() {
65 anyhow::bail!("Empty checks array");
66 }
67 if checks.len() > 10 {
68 anyhow::bail!("Maximum 10 checks per batch");
69 }
70
71 eprintln!("Creating {} payment checks...", checks.len());
72
73 let resp = api.batch_create_payment_checks(&key, &checks).await?;
74
75 for (i, check) in resp.checks.iter().enumerate() {
76 println!("--- Check {} ---", i + 1);
77 println!("check_id: {}", check.check_id);
78 println!("check_key: {}", check.check_key);
79 println!("amount: {}", check.amount);
80 if let Some(memo) = &check.memo {
81 println!("memo: {}", memo);
82 }
83 }
84
85 eprintln!("\nSave all check_keys — they are shown only once.");
86
87 Ok(())
88}
89
90pub async fn claim(
92 network: &NetworkConfig,
93 api_key: Option<&str>,
94 check_key: &str,
95 amount: Option<&str>,
96) -> Result<()> {
97 let key = resolve_wallet_key(api_key)?;
98 let api = ApiClient::new(network);
99
100 if let Some(amt) = amount {
101 eprintln!("Claiming {} from payment check...", amt);
102 } else {
103 eprintln!("Claiming payment check (full)...");
104 }
105
106 let resp = api.claim_payment_check(&key, check_key, amount).await?;
107
108 println!("token: {}", resp.token);
109 println!("claimed: {}", resp.amount_claimed);
110 println!("remaining: {}", resp.remaining);
111 if let Some(memo) = &resp.memo {
112 println!("memo: {}", memo);
113 }
114 println!("time: {}", resp.claimed_at);
115
116 eprintln!("\nFunds landed in your intents balance.");
117
118 Ok(())
119}
120
121pub async fn reclaim(
123 network: &NetworkConfig,
124 api_key: Option<&str>,
125 check_id: &str,
126 amount: Option<&str>,
127) -> Result<()> {
128 let key = resolve_wallet_key(api_key)?;
129 let api = ApiClient::new(network);
130
131 if let Some(amt) = amount {
132 eprintln!("Reclaiming {} from check {}...", amt, check_id);
133 } else {
134 eprintln!("Reclaiming check {} (full remaining)...", check_id);
135 }
136
137 let resp = api.reclaim_payment_check(&key, check_id, amount).await?;
138
139 println!("token: {}", resp.token);
140 println!("reclaimed: {}", resp.amount_reclaimed);
141 println!("remaining: {}", resp.remaining);
142 println!("time: {}", resp.reclaimed_at);
143
144 eprintln!("\nFunds returned to your intents balance.");
145
146 Ok(())
147}
148
149pub async fn status(
151 network: &NetworkConfig,
152 api_key: Option<&str>,
153 check_id: &str,
154) -> Result<()> {
155 let key = resolve_wallet_key(api_key)?;
156 let api = ApiClient::new(network);
157
158 let resp = api.get_payment_check_status(&key, check_id).await?;
159
160 println!("check_id: {}", resp.check_id);
161 println!("status: {}", resp.status);
162 println!("token: {}", resp.token);
163 println!("amount: {}", resp.amount);
164 println!("claimed: {}", resp.claimed_amount);
165 println!("reclaimed: {}", resp.reclaimed_amount);
166 if let Some(memo) = &resp.memo {
167 println!("memo: {}", memo);
168 }
169 println!("created: {}", resp.created_at);
170 if let Some(expires) = &resp.expires_at {
171 println!("expires: {}", expires);
172 }
173 if let Some(claimed_at) = &resp.claimed_at {
174 println!("claimed_at: {}", claimed_at);
175 }
176 if let Some(claimed_by) = &resp.claimed_by {
177 println!("claimed_by: {}", claimed_by);
178 }
179
180 Ok(())
181}
182
183pub async fn list(
185 network: &NetworkConfig,
186 api_key: Option<&str>,
187 status_filter: Option<&str>,
188 limit: i64,
189) -> Result<()> {
190 let key = resolve_wallet_key(api_key)?;
191 let api = ApiClient::new(network);
192
193 let resp = api
194 .list_payment_checks(&key, status_filter, limit)
195 .await?;
196
197 if resp.checks.is_empty() {
198 eprintln!("No payment checks found.");
199 return Ok(());
200 }
201
202 println!(
203 "{:<20} {:<18} {:>12} {:>12} {:<10}",
204 "CHECK_ID", "TOKEN", "AMOUNT", "CLAIMED", "STATUS"
205 );
206
207 for check in &resp.checks {
208 let token_short = if check.token.len() > 16 {
209 format!("{}...", &check.token[..14])
210 } else {
211 check.token.clone()
212 };
213 println!(
214 "{:<20} {:<18} {:>12} {:>12} {:<10}",
215 check.check_id, token_short, check.amount, check.claimed_amount, check.status
216 );
217 }
218
219 Ok(())
220}
221
222pub async fn sign_message(
224 network: &NetworkConfig,
225 api_key: Option<&str>,
226 message: &str,
227 recipient: &str,
228 nonce: Option<&str>,
229) -> Result<()> {
230 let key = resolve_wallet_key(api_key)?;
231 let api = ApiClient::new(network);
232
233 eprintln!("Signing message for {}...", recipient);
234
235 let resp = api.sign_message(&key, message, recipient, nonce).await?;
236
237 println!("account_id: {}", resp.account_id);
238 println!("public_key: {}", resp.public_key);
239 println!("signature: {}", resp.signature);
240 println!("nonce: {}", resp.nonce);
241
242 Ok(())
243}
244
245pub async fn peek(
247 network: &NetworkConfig,
248 api_key: Option<&str>,
249 check_key: &str,
250) -> Result<()> {
251 let key = resolve_wallet_key(api_key)?;
252 let api = ApiClient::new(network);
253
254 let resp = api.peek_payment_check(&key, check_key).await?;
255
256 println!("token: {}", resp.token);
257 println!("balance: {}", resp.balance);
258 println!("status: {}", resp.status);
259 if let Some(memo) = &resp.memo {
260 println!("memo: {}", memo);
261 }
262 if let Some(expires) = &resp.expires_at {
263 println!("expires: {}", expires);
264 }
265
266 Ok(())
267}