listen_kit/
transfer.rs

1use solana_client::nonblocking::rpc_client::RpcClient;
2use solana_sdk::pubkey::Pubkey;
3use solana_sdk::signature::Keypair;
4use solana_sdk::signer::Signer;
5use solana_sdk::transaction::Transaction;
6use std::error::Error;
7
8use crate::jito::send_jito_tx;
9
10pub async fn transfer_sol(
11    to: Pubkey,
12    amount: u64,
13    keypair: &Keypair,
14    rpc_client: &RpcClient,
15) -> Result<String, Box<dyn Error>> {
16    let from = keypair.pubkey();
17    let tx = Transaction::new_signed_with_payer(
18        &[solana_sdk::system_instruction::transfer(&from, &to, amount)],
19        None,
20        &[&keypair],
21        rpc_client.get_latest_blockhash().await?,
22    );
23    let res = send_jito_tx(tx).await?;
24
25    Ok(res)
26}
27
28pub async fn transfer_spl(
29    to: Pubkey,
30    amount: u64,
31    mint: Pubkey,
32    keypair: &Keypair,
33    rpc_client: &RpcClient,
34) -> Result<String, Box<dyn Error>> {
35    let from = keypair.pubkey();
36    let from_ata = spl_associated_token_account::get_associated_token_address(
37        &from, &mint,
38    );
39    let to_ata =
40        spl_associated_token_account::get_associated_token_address(&to, &mint);
41
42    let mut instructions = vec![];
43
44    // Check if recipient's ATA exists, if not create it
45    if rpc_client.get_account(&to_ata).await.is_err() {
46        instructions.push(
47            spl_associated_token_account::instruction::create_associated_token_account(
48                &from,
49                &to,
50                &mint,
51                &spl_token::id(),
52            ),
53        );
54    }
55
56    instructions.push(spl_token::instruction::transfer(
57        &spl_token::id(),
58        &from_ata,
59        &to_ata,
60        &from,
61        &[],
62        amount,
63    )?);
64
65    let tx = Transaction::new_signed_with_payer(
66        &instructions,
67        Some(&from),
68        &[keypair],
69        rpc_client.get_latest_blockhash().await?,
70    );
71
72    let res = send_jito_tx(tx).await?;
73
74    Ok(res)
75}
76
77#[cfg(test)]
78mod tests {
79    use solana_sdk::native_token::sol_to_lamports;
80    use solana_sdk::pubkey;
81    use solana_sdk::signer::Signer;
82
83    use super::*;
84    use crate::util::{load_keypair_for_tests, make_rpc_client};
85
86    #[tokio::test]
87    async fn test_transfer_sol() {
88        let keypair = load_keypair_for_tests();
89        let rpc_client = make_rpc_client();
90        let to = keypair.pubkey();
91        let amount = sol_to_lamports(0.0001);
92        let result = transfer_sol(to, amount, &keypair, &rpc_client).await;
93        assert!(result.is_ok());
94    }
95
96    #[tokio::test]
97    async fn test_transfer_spl() {
98        let keypair = load_keypair_for_tests();
99        let rpc_client = make_rpc_client();
100        let to = keypair.pubkey();
101        let mint = pubkey!("Cn5Ne1vmR9ctMGY9z5NC71A3NYFvopjXNyxYtfVYpump");
102        let amount = (1. * 1e6) as u64;
103        let result =
104            transfer_spl(to, amount, mint, &keypair, &rpc_client).await;
105        assert!(result.is_ok());
106    }
107}