Transferring SOL

  • Creating an Account

    use std::time::Duration;
    
    use anyhow::anyhow;
    use jsonrpsee::tracing::debug;
    use solana_program::system_program;
    use solana_sdk::{
        account::Account,
        signature::{Keypair, Signer},
    };
    use tokio::time::sleep;
    
    use crate::{client::TestClient, SLEEP_DURATION_SECONDS};
    
    /// Prepares a Solana transaction for a create_account instruction.
    /// Returns a base58-encoded string representation of the prepared transaction.
    pub fn prepare_new_account_transaction(
        payer: &Keypair,
        new_account: &Keypair,
        rent: u64,
        blockhash: Hash,
    ) -> Transaction {
        let instruction = system_instruction::create_account(
            &payer.pubkey(),
            &new_account.pubkey(),
            rent,
            0,
            &system_program::id(),
        );
    
        Transaction::new_signed_with_payer(
            &[instruction],
            Some(&payer.pubkey()),
            &[payer, new_account],
            blockhash,
        )
    }
    
    pub(crate) async fn create_account(
        client: &TestClient,
        payer: &Keypair,
        new_account: &Keypair,
        amount: u64,
    ) -> anyhow::Result<()> {
        debug!("Create new account");
        // Get initial balance
        let payer_initial_balance = client
            .svm_get_account_balance(payer.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to get payer's initial balance: {e}"))?;
    
        // Get latest blockhash
        let latest_blockhash = client
            .svm_get_latest_blockhash()
            .await
            .map_err(|e| anyhow!("Failed to retrieve the latest blockhash: {e}"))?;
    
        let create_acc_tx =
            prepare_new_account_transaction(payer, new_account, amount, latest_blockhash);
    
        let total_gas_fee_estimate = client
            .get_total_fee_for_transaction(&create_acc_tx)
            .await
            .map_err(|e| anyhow!("Failed to get total fee estimate for transaction: {e}"))?;
    
        let tx_hash = client
            .svm_send_transaction(&create_acc_tx)
            .await
            .map_err(|e| anyhow!("Failed to send a transaction: {e}"))?
            .to_string();
    
        // Wait for transactions to process and persist changes
        sleep(Duration::from_secs(SLEEP_DURATION_SECONDS)).await;
    
        // Check accounts and balances
        // Check payer's post balance
        let payer_post_balance = client
            .svm_get_account_balance(payer.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to get payer's post balance: {e}"))?;
        let expected_balance = payer_initial_balance - amount - total_gas_fee_estimate;
    
        // Check new account's post balance
        let new_acc_balance = client
            .svm_get_account_balance(new_account.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to get new account's balance: {e}"))?;
    
        // Check new account's info
        let new_acc_info = client
            .svm_get_account_info(new_account.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to retrieve new account: {e}"))?;
        let new_acc_key = new_account.pubkey();
    
        Ok(())
    }
  • Transferring SOL

    /// Prepares a Solana transaction for a transfer instruction.
    /// Returns a base58-encoded string representation of the prepared transaction.
    pub fn prepare_sol_transfer_transaction(
        payer: &Keypair,
        receiver: &Pubkey,
        lamports: u64,
        blockhash: Hash,
    ) -> Transaction {
        let instruction = system_instruction::transfer(&payer.pubkey(), receiver, lamports);
        Transaction::new_signed_with_payer(&[instruction], Some(&payer.pubkey()), &[payer], blockhash)
    }
    
    pub(crate) async fn transfer_sol(
        client: &TestClient,
        sender: &Keypair,
        receiver: &Keypair,
        amount: u64,
    ) -> anyhow::Result<()> {
        // Get initial balances
        let sender_initial_balance = client
            .svm_get_account_balance(sender.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to get sender's initial balance: {e}"))?;
        let receiver_initial_balance = client
            .svm_get_account_balance(receiver.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to get receiver's initial balance: {e}"))?;
    
        // Get latest blockhash
        let latest_blockhash = client
            .svm_get_latest_blockhash()
            .await
            .map_err(|e| anyhow!("Failed to retrieve the latest blockhash: {e}"))?;
    
        // Send and publish transaction
        let sol_transfer_tx =
            prepare_sol_transfer_transaction(sender, &receiver.pubkey(), amount, latest_blockhash);
    
        let total_gas_fee_estimate = client
            .get_total_fee_for_transaction(&sol_transfer_tx)
            .await
            .map_err(|e| anyhow!("Failed to get total fee estimate for transaction: {e}"))?;
    
        let tx_hash = client
            .svm_send_transaction(&sol_transfer_tx)
            .await
            .map_err(|e| anyhow!("Failed to send a transaction: {e}"))?
            .to_string();
    
        // Wait for transactions to process and persist changes
        sleep(Duration::from_secs(SLEEP_DURATION_SECONDS)).await;
    
        // Check balances post transfer
        // Check sender's post balance
        let sender_post_balance = client
            .svm_get_account_balance(sender.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to get sender's post balance: {e}"))?;
    
        // Check receiver's post balance
        let receiver_post_balance = client
            .svm_get_account_balance(receiver.pubkey())
            .await
            .map_err(|e| anyhow!("Failed to get receiver's post balance: {e}"))?;
    
        Ok(())
    }

Last updated

Was this helpful?