solagent_plugin_solana/
transfer.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 solagent_core::{
16    solana_client::client_error::ClientError,
17    solana_sdk::{
18        program_pack::Pack, pubkey::Pubkey, system_instruction, transaction::Transaction,
19    },
20    SolanaAgentKit,
21};
22use spl_associated_token_account::get_associated_token_address;
23use spl_token::{instruction::transfer as transfer_instruct, state::Mint};
24
25/// Transfer SOL or SPL tokens to a recipient
26///
27/// `agent` - SolanaAgentKit instance
28/// `to` - Recipient's public key
29/// `amount` - Amount to transfer
30/// `mint` - Optional mint address for SPL tokens
31///
32/// Returns the transaction signature.
33pub async fn transfer(
34    agent: &SolanaAgentKit,
35    to: &str,
36    amount: u64,
37    mint: Option<String>,
38) -> Result<String, ClientError> {
39    match mint {
40        Some(mint) => {
41            // Transfer SPL Token
42            let mint = Pubkey::from_str_const(&mint);
43            let to = Pubkey::from_str_const(to);
44
45            let from_ata = get_associated_token_address(&mint, &agent.wallet.pubkey);
46            let to_ata = get_associated_token_address(&mint, &to);
47
48            let account_info = &agent.connection.get_account(&mint).expect("get_account");
49            let mint_info = Mint::unpack_from_slice(&account_info.data).expect("unpack_from_slice");
50
51            let adjusted_amount = amount * 10u64.pow(mint_info.decimals as u32);
52
53            let transfer_instruction = transfer_instruct(
54                &spl_token::id(),
55                &from_ata,
56                &to_ata,
57                &from_ata,
58                &[&agent.wallet.pubkey],
59                adjusted_amount,
60            )
61            .expect("transfer_instruct");
62
63            let transaction = Transaction::new_signed_with_payer(
64                &[transfer_instruction],
65                Some(&agent.wallet.pubkey),
66                &[&agent.wallet.keypair],
67                agent
68                    .connection
69                    .get_latest_blockhash()
70                    .expect("new_signed_with_payer"),
71            );
72
73            let signature = agent
74                .connection
75                .send_and_confirm_transaction(&transaction)
76                .expect("send_and_confirm_transaction");
77            Ok(signature.to_string())
78        }
79        None => {
80            let transfer_instruction = system_instruction::transfer(
81                &agent.wallet.pubkey,
82                &Pubkey::from_str_const(to),
83                amount,
84            );
85            let transaction = Transaction::new_signed_with_payer(
86                &[transfer_instruction],
87                Some(&agent.wallet.pubkey),
88                &[&agent.wallet.keypair],
89                agent
90                    .connection
91                    .get_latest_blockhash()
92                    .expect("get_latest_blockhash"),
93            );
94
95            let signature = agent
96                .connection
97                .send_and_confirm_transaction(&transaction)
98                .expect("send_and_confirm_transaction");
99            Ok(signature.to_string())
100        }
101    }
102}