use std::path::PathBuf;
use aimo_client::types::transactions::{TopUpTxRequest, TransactionResponse};
use aimo_core::token_map::token_map;
use base64::Engine;
use bincode::config;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{message::Message, signature::Keypair, signer::Signer, transaction::Transaction};
use url::Url;
pub async fn top_up_escrow(
amount: f64,
id: Option<PathBuf>,
rpc_url: String,
router_url: String,
devnet_tokens: bool,
token: Option<String>,
) -> anyhow::Result<()> {
let token_map = token_map(devnet_tokens);
let token_name = token.unwrap_or("USDC".to_string());
let token = token_map
.find(&token_name)
.ok_or(anyhow::anyhow!("Token {token_name} isn't supported"))?;
let token_amount = (amount * 10_f64.powi(token.decimals as i32)) as u64;
if token_amount == 0 {
return Err(anyhow::anyhow!("Amount must be greater than 0"));
}
let fee_amount = token_amount
.checked_mul(3)
.ok_or_else(|| anyhow::anyhow!("Math overflow calculating fee"))?
.checked_div(100)
.ok_or_else(|| anyhow::anyhow!("Math overflow calculating fee"))?;
let total_amount = token_amount
.checked_add(fee_amount)
.ok_or_else(|| anyhow::anyhow!("Math overflow calculating total"))?;
let user_keypair = aimo_core::utils::id::create_keypair_from_file(id)?;
do_top_up(&user_keypair, token_name, total_amount, router_url, rpc_url).await?;
Ok(())
}
async fn do_top_up(
user: &Keypair,
token: String,
amount: u64,
router_url: String,
rpc_url: String,
) -> anyhow::Result<()> {
let client = RpcClient::new(rpc_url);
let block_hash = client.get_latest_blockhash().await?;
let tx = reqwest::Client::new()
.post(Url::parse(&format!(
"{router_url}/api/v1/users/topup/message"
))?)
.json(&TopUpTxRequest {
user_address: user.pubkey().to_string(),
token,
amount,
})
.send()
.await
.inspect(|r| tracing::debug!("Received response {:?}", r))?
.json::<TransactionResponse>()
.await
.map(|tx| tx.tx)
.map_err(anyhow::Error::from)
.and_then(|tx| {
base64::engine::general_purpose::STANDARD
.decode(tx)
.map_err(anyhow::Error::from)
})
.and_then(|tx| {
bincode::serde::decode_from_slice::<Message, _>(&tx[..], config::standard())
.map(|(tx, _)| tx)
.map_err(anyhow::Error::from)
})
.map(|msg| {
let mut transaction = Transaction::new_unsigned(msg);
transaction.sign(&[user], block_hash);
transaction
})?;
let tx = client
.send_and_confirm_transaction_with_spinner(&tx)
.await?;
println!("Top-up successful! Transaction signature: {}", tx);
Ok(())
}