outlayer_cli/commands/
earnings.rs1use anyhow::Result;
2use serde_json::json;
3
4use crate::api::ApiClient;
5use crate::config::{self, NetworkConfig};
6use crate::near::{ContractCaller, NearClient};
7
8pub async fn show(network: &NetworkConfig) -> Result<()> {
10 let creds = config::load_credentials(network)?;
11 let api = ApiClient::new(network);
12 let near = NearClient::new(network);
13
14 let https_earnings = api
16 .get_project_owner_earnings(&creds.account_id)
17 .await
18 .ok();
19
20 let blockchain_earnings = near.get_developer_earnings(&creds.account_id).await.ok();
22
23 let https_balance = https_earnings
24 .as_ref()
25 .map(|e| format_usd(&e.balance))
26 .unwrap_or_else(|| "$0.00".to_string());
27
28 let https_total = https_earnings
29 .as_ref()
30 .map(|e| format_usd(&e.total_earned))
31 .unwrap_or_else(|| "$0.00".to_string());
32
33 let blockchain_balance = blockchain_earnings
34 .as_ref()
35 .map(|e| format_usd(e))
36 .unwrap_or_else(|| "$0.00".to_string());
37
38 println!("Blockchain earnings: {blockchain_balance}");
39 println!("HTTPS API earnings: {https_balance} (total: {https_total})");
40
41 Ok(())
42}
43
44pub async fn withdraw(network: &NetworkConfig) -> Result<()> {
46 let creds = config::load_credentials(network)?;
47
48 let caller = ContractCaller::from_credentials(&creds, network)?;
49 let gas = 100_000_000_000_000u64; caller
52 .call_contract("withdraw_developer_earnings", json!({}), gas, 1) .await?;
54
55 eprintln!("Earnings withdrawn to {}", creds.account_id);
56 Ok(())
57}
58
59pub async fn history(
61 network: &NetworkConfig,
62 source: Option<String>,
63 limit: i64,
64) -> Result<()> {
65 let creds = config::load_credentials(network)?;
66 let api = ApiClient::new(network);
67
68 let resp = api
69 .get_earnings_history(&creds.account_id, source.as_deref(), limit, 0)
70 .await?;
71
72 if resp.earnings.is_empty() {
73 eprintln!("No earnings history.");
74 return Ok(());
75 }
76
77 println!(
78 "{:<12} {:<10} {:<25} {:>10}",
79 "DATE", "SOURCE", "PROJECT", "AMOUNT"
80 );
81
82 for e in &resp.earnings {
83 let date = format_timestamp(e.created_at);
84 let amount = format_usd(&e.amount);
85 println!(
86 "{:<12} {:<10} {:<25} {:>10}",
87 date, e.source, e.project_id, amount
88 );
89 }
90
91 if resp.total_count > limit {
92 eprintln!(
93 "\nShowing {}/{} entries. Use --limit to see more.",
94 resp.earnings.len(),
95 resp.total_count
96 );
97 }
98
99 Ok(())
100}
101
102fn format_usd(minimal_units: &str) -> String {
104 let units: u64 = minimal_units.parse().unwrap_or(0);
105 let dollars = units as f64 / 1_000_000.0;
106 format!("${:.2}", dollars)
107}
108
109fn format_timestamp(ts: i64) -> String {
110 let secs = if ts > 1_000_000_000_000 {
112 ts / 1000
113 } else {
114 ts
115 };
116 let days_since_epoch = secs / 86400;
118 let year = 1970 + (days_since_epoch / 365);
120 let day_in_year = days_since_epoch % 365;
121 let month = day_in_year / 30 + 1;
122 let day = day_in_year % 30 + 1;
123 format!("{:04}-{:02}-{:02}", year, month, day)
124}