1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//! Vault and strategy report queries from Kong API
use crate::client::Client;
use crate::error::Result;
use crate::types::{StrategyReport, VaultReport};
use serde::Deserialize;
/// Reports API for vault and strategy performance data
pub struct ReportsApi<'a> {
client: &'a Client,
}
impl<'a> ReportsApi<'a> {
/// Create a new reports API instance
#[must_use]
pub fn new(client: &'a Client) -> Self {
Self { client }
}
/// Get vault reports (harvest events)
///
/// # Example
///
/// ```no_run
/// # async fn example() -> ykong::error::Result<()> {
/// use ykong::Client;
///
/// let client = Client::new()?;
/// let reports = client.reports().vault_reports(1, "0x...").await?;
/// for report in reports {
/// if let Some(gain) = report.gain_usd {
/// println!("Harvest gain: ${:.2}", gain);
/// }
/// }
/// # Ok(())
/// # }
/// ```
pub async fn vault_reports(&self, chain_id: u64, address: &str) -> Result<Vec<VaultReport>> {
let query = format!(
r#"{{
vaultReports(chainId: {chain_id}, address: "{address}") {{
chainId
address
eventName
strategy
gain
loss
debtPaid
totalGain
totalLoss
totalDebt
debtAdded
debtRatio
currentDebt
protocolFees
totalFees
totalRefunds
gainUsd
lossUsd
debtPaidUsd
totalGainUsd
totalLossUsd
totalDebtUsd
debtAddedUsd
currentDebtUsd
protocolFeesUsd
totalFeesUsd
totalRefundsUsd
priceUsd
priceSource
apr {{ gross net forward }}
blockNumber
blockTime
logIndex
transactionHash
}}
}}"#
);
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct Response {
vault_reports: Vec<VaultReport>,
}
let response: Response = self.client.query(&query).await?;
Ok(response.vault_reports)
}
/// Get strategy reports (harvest events)
///
/// # Example
///
/// ```no_run
/// # async fn example() -> ykong::error::Result<()> {
/// use ykong::Client;
///
/// let client = Client::new()?;
/// let reports = client.reports().strategy_reports(1, "0x...").await?;
/// for report in reports {
/// if let Some(profit) = report.profit_usd {
/// println!("Strategy profit: ${:.2}", profit);
/// }
/// }
/// # Ok(())
/// # }
/// ```
pub async fn strategy_reports(
&self,
chain_id: u64,
address: &str,
) -> Result<Vec<StrategyReport>> {
let query = format!(
r#"{{
strategyReports(chainId: {chain_id}, address: "{address}") {{
chainId
address
eventName
profit
loss
debtPayment
debtOutstanding
protocolFees
performanceFees
apr {{ gross net forward }}
profitUsd
lossUsd
debtPaymentUsd
debtOutstandingUsd
protocolFeesUsd
performanceFeesUsd
priceUsd
priceSource
blockNumber
blockTime
logIndex
transactionHash
}}
}}"#
);
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct Response {
strategy_reports: Vec<StrategyReport>,
}
let response: Response = self.client.query(&query).await?;
Ok(response.strategy_reports)
}
/// Get the latest vault report
pub async fn latest_vault_report(
&self,
chain_id: u64,
address: &str,
) -> Result<Option<VaultReport>> {
let reports = self.vault_reports(chain_id, address).await?;
Ok(reports.into_iter().next())
}
/// Get the latest strategy report
pub async fn latest_strategy_report(
&self,
chain_id: u64,
address: &str,
) -> Result<Option<StrategyReport>> {
let reports = self.strategy_reports(chain_id, address).await?;
Ok(reports.into_iter().next())
}
/// Calculate total gains from vault reports
pub async fn vault_total_gains_usd(&self, chain_id: u64, address: &str) -> Result<f64> {
let reports = self.vault_reports(chain_id, address).await?;
let total = reports.iter().filter_map(|r| r.gain_usd).sum();
Ok(total)
}
/// Calculate total gains from strategy reports
pub async fn strategy_total_profits_usd(&self, chain_id: u64, address: &str) -> Result<f64> {
let reports = self.strategy_reports(chain_id, address).await?;
let total = reports.iter().filter_map(|r| r.profit_usd).sum();
Ok(total)
}
}