solagent/tools/
trade.rs

1// Copyright 2025 zTgx
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::{actions::trade, parameters_json_schema, SolanaAgentKit};
16use rig::{
17    completion::ToolDefinition,
18    tool::{Tool, ToolEmbedding},
19};
20use serde::{Deserialize, Serialize};
21use serde_json::json;
22use std::sync::Arc;
23
24#[derive(Deserialize)]
25pub struct TradeArgs {
26    output_mint: String,
27    input_amount: f64,
28    input_mint: Option<String>,
29    slippage_bps: Option<u32>,
30}
31
32#[derive(Deserialize, Serialize)]
33pub struct TradeOutput {
34    pub signature: String,
35}
36
37#[derive(Debug, thiserror::Error)]
38#[error("Trade error")]
39pub struct TradeError;
40
41pub struct Trade {
42    agent: Arc<SolanaAgentKit>,
43}
44
45impl Trade {
46    pub fn new(agent: Arc<SolanaAgentKit>) -> Self {
47        Trade { agent }
48    }
49}
50
51impl Tool for Trade {
52    const NAME: &'static str = "trade";
53
54    type Error = TradeError;
55    type Args = TradeArgs;
56    type Output = TradeOutput;
57
58    async fn definition(&self, _prompt: String) -> ToolDefinition {
59        ToolDefinition {
60            name: "trade".to_string(),
61            description: r#"
62            This tool can be used to swap tokens to another token (It uses Jupiter Exchange).
63
64            [
65                {
66                    input: {
67                        outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
68                        inputAmount: 1,
69                    },
70                    explanation: "Swap 1 SOL for USDC",
71                },
72                ],
73                [
74                {
75                    input: {
76                        outputMint: "So11111111111111111111111111111111111111112",
77                        inputAmount: 100,
78                        inputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
79                        slippageBps: 100,
80                    },
81                    explanation: "Swap 100 USDC for SOL with 1% slippage",
82                },
83            ],
84            
85            "#
86            .to_string(),
87            parameters: parameters_json_schema!(
88                output_mint: String,
89                input_amount: f64,
90                input_mint: String,
91                slippage_bps: u32,
92            ),
93        }
94    }
95
96    async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
97        let signature = trade(&self.agent, &args.output_mint, args.input_amount, args.input_mint, args.slippage_bps)
98            .await
99            .expect("trade");
100
101        Ok(TradeOutput { signature })
102    }
103}
104
105#[derive(Debug, thiserror::Error)]
106#[error("Init error")]
107pub struct InitError;
108
109impl ToolEmbedding for Trade {
110    type InitError = InitError;
111    type Context = ();
112    type State = Arc<SolanaAgentKit>;
113
114    fn init(_state: Self::State, _context: Self::Context) -> Result<Self, Self::InitError> {
115        Ok(Trade { agent: _state })
116    }
117
118    fn embedding_docs(&self) -> Vec<String> {
119        vec!["This tool can be used to swap tokens to another token (It uses Jupiter Exchange).".into()]
120    }
121
122    fn context(&self) -> Self::Context {}
123}