use crate::client::SorobanRpcClient;
use crate::error::RpcError;
use serde::Serialize;
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct TtlInfo {
pub contract_id: String,
pub entries: Vec<TtlEntry>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct TtlEntry {
pub key: String,
pub current_ttl: u32,
pub expiration_time: String,
pub days_remaining: u32,
pub extension_cost_stroops: u64,
}
pub fn calculate_extension_cost(ledger_delta: u32) -> u64 {
ledger_delta as u64 * 100
}
pub async fn get_ttl_info(
client: &SorobanRpcClient,
contract_id: &str,
) -> Result<TtlInfo, RpcError> {
let ledger_info = client.get_ledger().await?;
let current_ledger = ledger_info.sequence;
let storage_resp = client.get_contract_storage(contract_id, &[]).await?;
let mut entries = Vec::new();
for entry in storage_resp.entries {
let current_ttl = if let Some(live_until) = entry.live_until_ledger_seq {
live_until.saturating_sub(current_ledger)
} else {
0
};
let days_remaining = (current_ttl * 5) / (24 * 3600);
let extension_cost_stroops = calculate_extension_cost(current_ttl);
entries.push(TtlEntry {
key: entry.key,
current_ttl,
expiration_time: format!("~{} days", days_remaining),
days_remaining,
extension_cost_stroops,
});
}
Ok(TtlInfo {
contract_id: contract_id.to_string(),
entries,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculate_extension_cost() {
const SINGLE_ENTRY_TTL_30: u32 = 30;
const SINGLE_ENTRY_TTL_100: u32 = 100;
assert_eq!(calculate_extension_cost(SINGLE_ENTRY_TTL_30), 3000);
assert_eq!(calculate_extension_cost(SINGLE_ENTRY_TTL_100), 10000);
assert_eq!(calculate_extension_cost(0), 0);
}
}