use std::str::FromStr;
use amico::{
ai::tool::{Tool, ToolBuilder},
environment::Sensor,
resource::{IntoResource, Resource},
};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use solana_client::client_error::ClientError;
use solana_sdk::{native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, signer::Signer};
use crate::web3::wallet::WalletResource;
use super::client::SolanaClientResource;
#[derive(Clone)]
pub struct BalanceSensor {
client: SolanaClientResource,
wallet: WalletResource,
}
impl BalanceSensor {
pub fn new(client: SolanaClientResource, wallet: WalletResource) -> Self {
Self { client, wallet }
}
pub fn agent_wallet_balance_tool(&self) -> Tool {
let pubkey = self.wallet.get().solana().pubkey();
let sensor = self.clone();
ToolBuilder::new()
.name("balance_sensor")
.description("Get the balance of your own Solana account.")
.parameters(serde_json::json!({}))
.build_async(move |_| {
let sensor = sensor.clone();
let pubkey = pubkey;
async move {
sensor
.sense(BalanceSensorArgs { pubkey })
.await
.map(|result| {
serde_json::json!({
"balance": result.lamports as f64 / LAMPORTS_PER_SOL as f64
})
})
}
})
}
pub fn account_balance_tool(&self) -> Tool {
let sensor = self.clone();
ToolBuilder::new()
.name("account_balance_tool")
.description("Get the balance of a Solana account.")
.parameters(serde_json::json!({
"type": "object",
"properties": {
"pubkey": {
"type": "string",
"description": "The Solana pubkey of the account."
}
},
"required": ["pubkey"],
}))
.build_async(move |args| {
let sensor = sensor.clone();
let pubkey_arg = args["pubkey"].to_string();
async move {
let pubkey = Pubkey::from_str(&pubkey_arg)?;
sensor
.sense(BalanceSensorArgs { pubkey })
.await
.map(|result| {
serde_json::json!({
"balance": result.lamports as f64 / LAMPORTS_PER_SOL as f64
})
})
}
})
}
}
impl IntoResource<BalanceSensor> for BalanceSensor {
fn into_resource(self) -> Resource<BalanceSensor> {
Resource::new("balance_sensor", self)
}
}
#[derive(Debug, thiserror::Error)]
pub enum BalanceSensorError {
#[error("Failed to get balance: {0}")]
GetBalanceError(#[from] ClientError),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BalanceSensorArgs {
pub pubkey: Pubkey,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BalanceSensorResult {
pub lamports: u64,
}
#[async_trait]
impl Sensor for BalanceSensor {
type Args = BalanceSensorArgs;
type Output = BalanceSensorResult;
async fn sense(&self, args: Self::Args) -> anyhow::Result<Self::Output> {
let lamports = self
.client
.get()
.rpc_client()
.get_balance(&args.pubkey)
.await?;
Ok(BalanceSensorResult { lamports })
}
}