Solana world for Rustaceans

Solana is a decentralized blockchain built to enable scalable, user-friendly apps for the world. I think it is the best choice for a promising career because this is a new blockchain, but despite this, it has already gained huge popularity. Solana is the fastest blockchain in the world and the fastest growing ecosystem in crypto.

Why Rust?

  • quick
  • safe
  • popular

Safety, easy multi-platform development, speed, and quality is just what blockchain developers need - and where Rust excels.

Are you concerned about the question: do you need blockchain experience to understand how to build on Solana?

The very first thing that I think is important for any new developer coming into the Solana Ecosystem to understand is that it is not a requirement that you have experience with smart contracts or Rust to get started building on Solana. In fact, you don’t need blockchain experience at all. -Chase Barker

Smart Contract

In this article, you will try to develop a smart contract that will send SOL from the created account in the program to Phantom Wallet.

P.S I assume you have already installed Rust!

Phantom Wallet

I use the Phantom Wallet for Solana development. So, you need to create a new wallet:

Screenshot_2022-05-23 22-33-32.jpg

Screenshot_2022-05-23 22-39-41.jpg

Screenshot_2022-05-23 22-41-21.jpg

Screenshot_2022-05-23 22-43-03.jpg

Warning! You have to remember the secret recovery phrase (save it) for future work with your wallet!

Z2gOZ-L27.png

Getting Started

Project creating

First of all, you need to create a rust project:

cargo new --bin transfer

Navigate to the folder containing the project and open your project in IDE.

For the correct project structure, let's create a new file and name it operations.rs. As a result, your project structure will look so:

изображение_2022-05-23_135900541.png

Adding dependencies

Then you need to add some dependencies to Cargo.toml file:

[dependencies]
solana-sdk = "1.10.0"
solana-client = "1.10.0"
solana-program = "1.7.14"

Click to crate name to check the newest version and study more:

solana-sdk crate

solana-client crate

solana-program crate

Let's write a smart contract logic!

At first, we will work with the operations.rs file.

new_keypair()

This is a function that creates a new keypair.

Import necessary for new_keypair function:

use solana_sdk::signature::Keypair;

Code:

pub fn new_keypair() -> Keypair {
    Keypair::new()
}

check_balance()

This function allows us to check our account balance.

Import necessary for check_balance function:

use std::error::Error;
use solana_client::rpc_client::RpcClient;
use solana_program::pubkey::Pubkey;

Then create a constant LAMPORTS_PER_SOL:

const LAMPORTS_PER_SOL: f64 = 1000000000.0;

The input data of the method is provided in SOL, but we need in lamports. So, we create constant which is equal to the amount lamports in 1 SOL.

Code:

pub fn check_balance(rpc_client: &RpcClient, public_key: &Pubkey) -> Result<f64, Box<dyn Error>> {
    Ok(rpc_client.get_balance(&public_key)? as f64 / LAMPORTS_PER_SOL)
}

airdrop()

This one request an airdrop.

Import necessary for airdrop function:

use solana_sdk::signature::Signature;

Code:

pub fn airdrop(rpc_client: &RpcClient, pub_key: &Pubkey, amount_sol: f64) -> Result<Signature, Box<dyn Error>> {
    let sig = rpc_client.request_airdrop(&pub_key, (amount_sol * LAMPORTS_PER_SOL) as u64)?;
    loop {
        let confirmed = rpc_client.confirm_transaction(&sig)?;
        if confirmed {
            break;
        }
    }
    Ok(sig)
}

transfer()

Makes a transfer between the created account and the wallet.

Code:

pub fn transfer(rpc_client: &RpcClient, sender_keypair: &Keypair, receiver_pub_key: &Pubkey, amount_sol: f64) 
        -> core::result::Result<Signature, Box<dyn Error>> {
    let amount_lamports = (amount_sol * LAMPORTS_PER_SOL) as u64;
    Ok(rpc_client.send_and_confirm_transaction(
        &system_transaction::transfer(
            &sender_keypair, &receiver_pub_key, 
            amount_lamports, 
            rpc_client.get_latest_blockhash()?))?)


}

Your operations.rs file needs to look like this:

use std::error::Error;
use solana_client::rpc_client::RpcClient;
use solana_program::pubkey::Pubkey;
use solana_sdk::{system_transaction, signature::{Keypair, Signature}};

const LAMPORTS_PER_SOL: f64 = 1000000000.0;

pub fn new_keypair() -> Keypair {
    Keypair::new()
}

pub fn check_balance(rpc_client: &RpcClient, public_key: &Pubkey) -> Result<f64, Box<dyn Error>> {
    Ok(rpc_client.get_balance(&public_key)? as f64 / LAMPORTS_PER_SOL)
}

pub fn airdrop(rpc_client: &RpcClient, pub_key: &Pubkey, amount_sol: f64) -> Result<Signature, Box<dyn Error>> {
    let sig = rpc_client.request_airdrop(&pub_key, (amount_sol * LAMPORTS_PER_SOL) as u64)?;
    loop {
        let confirmed = rpc_client.confirm_transaction(&sig)?;
        if confirmed {
            break;
        }
    }
    Ok(sig)
}

pub fn transfer(rpc_client: &RpcClient, sender_keypair: &Keypair, receiver_pub_key: &Pubkey, amount_sol: f64) 
        -> core::result::Result<Signature, Box<dyn Error>> {
    let amount_lamports = (amount_sol * LAMPORTS_PER_SOL) as u64;
    Ok(rpc_client.send_and_confirm_transaction(
        &system_transaction::transfer(
            &sender_keypair, &receiver_pub_key, 
            amount_lamports, 
            rpc_client.get_latest_blockhash()?))?)


}

Then we will work Phantom Wallet.

As you know, our smart contract will make transactions between created account and Phantom Wallet. So, you need to get your wallet keypair.

Run this command in the terminal:

 solana-keygen recover 'prompt:?key=0/0' --outfile keypair.json

This command will create a new file called keypair.json. So, be sure you were in your project directory in your terminal when you have run this one.

image.png

You have to write the secret recovery phrase you have saved when creating a Phantom Wallet.

Screenshot_2022-05-23 22-43-043.jpg

Then follow the steps terminal ask. Congratulations! keypair.json file has been created!

Changing network on Phantom Wallet

For work with our program, we will use Devnet network. So we need to set thin one on Phantom Wallet settings.

11.jpg

22.jpg

33.jpg

Then we will work with the main.rs file.

First of all, you need to import our functions from operations.rs to main.rs

mod operations;

You need to create an RPC client on main.rs, that will be injected in the functions: airdrop(), check_balance() and transfer().

const URL: &str = "https://api.devnet.solana.com";

Warning! We use Solana Devnet, so you need to run "solana config set --url https://api.devnet.solana.com" in your terminal

Let's create RPC client:

Import:

use solana_client::rpc_client::RpcClient;

Code:

 let rpc_client = RpcClient::new(URL);

Then you need to create sender:

Import:

use solana_sdk::signature::Keypair;
    let sender = lib::create_keypair();

Let's create receiver!

Open your keypair.json file and copy the content.

Create a receiver:

    let receiver = Keypair::from_bytes(&[78,191,0,2,163,138,129,56,151,229,72,236,119,17,18,47,52,252,251,220,75,238,231,245,170,123,230,224,166,3,26,7,15,185,50,207,55,49,241,241,101,60,84,179,213,56,221,0,117,76,36,141,63,207,196,223,87,126,116,38,80,199,161,13]).unwrap();;

Import:

use solana_sdk::signer::Signer;

Then we request an airdrop for the sender with airdrop of 1 SOL. We can also check balance using check_balance. In the end, we need to call the transfer function.

Code:

if let Ok(_) = operations::airdrop(&rpc_client, &sender_key.pubkey(), 1.0) {
        if let Ok(balance) = operations::check_balance(&rpc_client, &sender_key.pubkey()) {
            println!("Sender balance now: {:?}", balance);
        }

        let transfer_amount = 0.5;

        match operations::transfer(&rpc_client, &sender_key, &receiver_key.pubkey(), transfer_amount) {
            Ok(_) => { 
                if let Ok(balance) = operations::check_balance(&rpc_client, &sender_key.pubkey()) {
                    println!("Sender balance after transaction: {:?}", balance);
                }
                if let Ok(balance) = operations::check_balance(&rpc_client, &receiver_key.pubkey()) {
                    println!("Receiver balance after transaction: {:?}", balance);
                }
            },
            Err(err) => println!("Error: {:?}", err),
        }
    } else {
        println!("Failed");
    }

Your main.rs file needs to look like this:

mod operations;
use solana_sdk::signer::Signer;
use solana_client::rpc_client::RpcClient;
use solana_sdk::signature::Keypair;
const URL: &str = "https://api.devnet.solana.com";

fn main() {
    let rpc_client = RpcClient::new(URL);
    let sender_key = operations::new_keypair();
    let receiver_key = Keypair::from_bytes(&[78,191,0,2,163,138,129,56,151,229,72,236,119,17,18,47,52,252,251,220,75,238,231,245,170,123,230,224,166,3,26,7,15,185,50,207,55,49,241,241,101,60,84,179,213,56,221,0,117,76,36,141,63,207,196,223,87,126,116,38,80,199,161,13]).unwrap();

    if let Ok(_) = operations::airdrop(&rpc_client, &sender_key.pubkey(), 1.0) {
        if let Ok(balance) = operations::check_balance(&rpc_client, &sender_key.pubkey()) {
            println!("Sender balance now: {:?}", balance);
        }

        let transfer_amount = 0.5;

        match operations::transfer(&rpc_client, &sender_key, &receiver_key.pubkey(), transfer_amount) {
            Ok(_) => { 
                if let Ok(balance) = operations::check_balance(&rpc_client, &sender_key.pubkey()) {
                    println!("Sender balance after transaction: {:?}", balance);
                }
                if let Ok(balance) = operations::check_balance(&rpc_client, &receiver_key.pubkey()) {
                    println!("Receiver balance after transaction: {:?}", balance);
                }
            },
            Err(err) => println!("Error: {:?}", err),
        }
    } else {
        println!("Failed");
    }
}

Congratulations! That is all! We have finished!

Now run in the terminal:

cargo run

изображение_2022-05-24_102732949.png

GitHub repository with source code:

Other useful sources:

The thing I like the most - Telegram chat and Solana Discord channels are always active! You can ask for help and other developers will help you. P.S On Discord, the channels are divided into subgroups, so it will be easier for you to find answers to certain topics.

Solana Tech Discord

Solana Telegram

More...

1
Subscribe to my newsletter

Read articles from Yelyzaveta Dymchenko directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Yelyzaveta Dymchenko
Yelyzaveta Dymchenko