How to Transfer SOL and SPL Tokens Using Anchor

Posted By : Ashish

Mar 29, 2024

The Anchor framework is a Rust-based framework for building Solana programs using Solana blockchain development. It simplifies the process of developing Solana smart contracts by providing a higher-level abstraction over Solana's low-level programming model. Anchor abstracts away much of the complexity involved in writing Solana programs, making it easier for developers to focus on application logic rather than low-level details.

 

Prerequisites

 

Rust Installation

 

Go here to install Rust.

 

Solana Installation

 

To set up Solana, visit the Solana website to download and install the software. Once installed, open your terminal and run the command `solana-keygen new` to generate a key pair. This will create a keypair at the default location.

 

Yarn Installation

 

Go here to install Yarn.

 

Anchor Installation

 

Installing using Anchor version manager

 

Anchor version manager is a tool for using multiple versions of the anchor-cli. It will require the same dependencies as building from source. It is recommended you uninstall the NPM package if you have it installed.

 

Install avm using Cargo. Note this will replace your anchor binary if you had one installed.

 

cargo install --git https://github.com/coral-xyz/anchor avm --locked --force

 

On Linux systems, you may need to install additional dependencies if the cargo install fails. E.g. on Ubuntu:

 

Install the latest version of the CLI using AVM, and then set it to be the version to use.

 

avm install latest
avm use latest

Verify the installation.
anchor --version
Steps 

 

1.) Initialize a new project, simply run:

 

anchor init <new-workspace-name>

 

2.) Let's begin by opening lib.rs in the programs folder, we can proceed with developing our program.

 

3.) Below is the program code

 

use anchor_lang::prelude::*;
use anchor_spl::token::{self, Token, TokenAccount, Transfer as SplTransfer};
use solana_program::system_instruction;

declare_id!("MyUniqueProgramId");

#[program]
pub mod my_program {
use super::*;

// Function for transferring lamports
pub fn transfer_lamports(ctx: Context<LamportTransfer>, amount: u64) -> Result<()> {
     let sender_account = &ctx.accounts.sender;
     let recipient_account = &ctx.accounts.recipient;

     // Create the transfer instruction
     let transfer_instruction =
         system_instruction::transfer(sender_account.key, recipient_account.key, amount);

     // Invoke the transfer instruction
     anchor_lang::solana_program::program::invoke_signed(
         &transfer_instruction,
         &[
             sender_account.to_account_info(),
             recipient_account.clone(),
             ctx.accounts.system_program.to_account_info(),
         ],
         &[],
     )?;

     Ok(())
}

// Function for transferring SPL tokens
pub fn transfer_spl_tokens(ctx: Context<SplTokenTransfer>, amount: u64) -> Result<()> {
     let destination_account = &ctx.accounts.destination_token_account;
     let source_account = &ctx.accounts.source_token_account;
     let token_program = &ctx.accounts.spl_token_program;
     let authority = &ctx.accounts.authority;

     // Transfer tokens from source to destination
     let cpi_accounts = SplTransfer {
         from: source_account.to_account_info().clone(),
         to: destination_account.to_account_info().clone(),
         authority: authority.to_account_info().clone(),
     };
     let cpi_program = token_program.to_account_info();

     // Invoke SPL token transfer
     token::transfer(CpiContext::new(cpi_program, cpi_accounts), amount)?;

     Ok(())
}
}

// Accounts for transferring lamports
#[derive(Accounts)]
pub struct LamportTransfer<'info> {
#[account(mut)]
pub sender: Signer<'info>,
#[account(mut)]
pub recipient: AccountInfo<'info>,
pub system_program: Program<'info, System>,
}

// Accounts for transferring SPL tokens
#[derive(Accounts)]
pub struct SplTokenTransfer<'info> {
pub authority: Signer<'info>,
#[account(mut)]
pub source_token_account: Account<'info, TokenAccount>,
#[account(mut)]
pub destination_token_account: Account<'info, TokenAccount>,
pub spl_token_program: Program<'info, Token>,
}

 

4.)Let's break down the code and explain the program:

 

  1. Imports:
    • anchor_lang::prelude::*: Imports the necessary items from the Anchor framework's prelude module, providing convenient access to commonly used types and traits.
    • anchor_spl::token::{self, Token, TokenAccount, Transfer as SplTransfer}: Imports types related to SPL tokens from the Anchor SPL module, including the Token, TokenAccount, and Transfer structs.
    • solana_program::system_instruction: Imports the system instruction module from Solana's program library, which includes functions for interacting with the system program.
  2. Program ID Declaration:
    • declare_id!("MyUniqueProgramId"): Declares a unique program ID for the Solana program. This macro generates the declaration of a constant representing the program ID.
  3. Program Module:
    • #[program] mod my_program { ... }: Defines a module named my_program that represents the Solana program. The #[program] attribute is a procedural macro provided by Anchor, which generates necessary code to define the Solana program.
  4. Function Definitions:
    • Within the my_program module, two functions are defined:
      • transfer_lamports: Handles the transfer of Solana lamports (the native token of the Solana blockchain).
      • transfer_spl_tokens: Handles the transfer of SPL tokens.
  5. Function Parameters:
    • Both functions take a Context parameter, which provides access to program accounts and environment data required for the execution of the function. The Context is a generic type parameterized by a struct representing the accounts required for the function.
  6. Function Bodies:
    • transfer_lamports: This function transfers a specified amount of lamports from one account to another using the system program's transfer instruction. It constructs the transfer instruction and invokes it using Anchor's invoke_signed function, passing required accounts and signers.
    • transfer_spl_tokens: This function transfers a specified amount of SPL tokens from one account to another using the SPL token program's transfer instruction. It constructs the transfer instruction and invokes it using Anchor's token::transfer function, passing required accounts and amount.
  7. Account Structs:
    • TransferLamports and SplTokenTransfer are account structs defined using the #[derive(Accounts)] attribute. These structs represent the accounts required by the respective transfer functions. Account structs define the accounts that the Solana program will interact with, including the types of those accounts (e.g., Signer, Account, Program). Each field in the account struct corresponds to an account used by the program.
  8. Account Attributes:
    • Account fields in the structs are decorated with attributes that specify their properties:
      • #[account(mut)]: Indicates that the account is mutable, allowing the program to modify its data.
      • #[account(signer)]: Specifies that the account must be a signer, providing authorization for transactions.

 

To get started with Solana blockchain development or a project development on Solana, connect with our blockchain developers

Leave a

Comment

Name is required

Invalid Name

Comment is required

Recaptcha is required.

blog-detail

April 29, 2024 at 09:07 pm

Your comment is awaiting moderation.

By using this site, you allow our use of cookies. For more information on the cookies we use and how to delete or block them, please read our cookie notice.

Chat with Us
Contact Us

Oodles | Blockchain Development Company

Name is required

Please enter a valid Name

Please enter a valid Phone Number

Please remove URL from text