Skip to content

Build a native Solana program to create initialize an account, deposit SOL into it, and withdraw 10% of the deposited SOL at a given time from it.

Notifications You must be signed in to change notification settings

4rjunc/sol-vault

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Detailed Explanation of Solana Program

1. lib.rs

pub mod instruct;
pub mod process;

use {crate::process::process_instruction, solana_program::entrypoint};

entrypoint!(process_instruction);

Let's break this down:

  1. pub mod instruct; and pub mod process;: These lines declare public modules. Modules in Rust are ways to organize code. Here, we're saying that there are two modules named "instruct" and "process" that are part of this program.

  2. use {crate::process::process_instruction, solana_program::entrypoint};: This line is importing (bringing into scope) the process_instruction function from the process module in the current crate (crate means package in Rust), and the entrypoint macro from the solana_program crate.

  3. entrypoint!(process_instruction);: This is using the entrypoint macro to declare that process_instruction is the entry point of this Solana program. When the program is invoked, this function will be called.

2. process.rs

use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::AccountInfo,
    entrypoint::ProgramResult,
    pubkey::Pubkey
};

use crate::instruct::*;

#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub enum NativeVaultInstruction {
    Initialize(),
    Deposit(u64),
    PartialWithdraw(),
}

pub fn process_instruction(
    program_id: &Pubkey,
    accounts  : &[AccountInfo],
    input     : &[u8],
) -> ProgramResult {
    let instruction: NativeVaultInstruction = NativeVaultInstruction::try_from_slice(input)?;

    match instruction {
        NativeVaultInstruction::Initialize() => initialize(
            program_id,
            accounts,
        ),

        NativeVaultInstruction::Deposit(args) => deposit(
            program_id,
            accounts,
            args
        ),

        NativeVaultInstruction::PartialWithdraw() => partial_withdraw(
            program_id,
            accounts,
        ),
    }
}

Let's break this down:

  1. The use statements at the top are importing necessary types and traits from the borsh and solana_program crates, as well as everything from the instruct module.

  2. #[derive(BorshSerialize, BorshDeserialize, Debug)]: This is an attribute that automatically implements serialization, deserialization, and debug formatting for the following enum.

  3. pub enum NativeVaultInstruction: This defines an enumeration of the possible instructions that this program can handle: Initialize, Deposit, and PartialWithdraw.

  4. pub fn process_instruction: This is the main entry point of the program. It takes three parameters:

    • program_id: The public key of the program.
    • accounts: A slice of AccountInfo structures, representing the accounts involved in the transaction.
    • input: A byte slice containing the instruction data.
  5. Inside process_instruction:

    • It first deserializes the input into a NativeVaultInstruction.
    • Then it uses a match statement to call the appropriate function based on the instruction type.

3. instruct.rs

This file contains the main logic of the program. Let's break it down into sections:

Imports and Struct Definitions

use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint::ProgramResult,
    program::{invoke, invoke_signed},
    program_error::ProgramError,
    pubkey::Pubkey,
    rent::Rent,
    system_instruction, sysvar::{clock::Clock, Sysvar},
};

#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct Vault {
    pub owner  : Pubkey,
}

#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct Pda {
    pub signer      : Pubkey,
    pub balance     : u64,
    pub deposit_time: i64,
    pub done        : bool,
}

pub const DELAY: i64 = 10;
pub const TAG_SSF_PDA: &[u8; 9] = b"SOL_VAULT";

This section imports necessary modules and defines two structs: Vault and Pda. It also defines some constants.

Initialize Function

pub fn initialize(
    program_id: &Pubkey,
    accounts  : &[AccountInfo]
) -> ProgramResult {
    // ... (implementation details)
}

This function initializes a new vault. It:

  1. Extracts necessary accounts from the accounts slice.
  2. Calculates the minimum rent required for the vault account.
  3. Creates a new account for the vault.
  4. Initializes the vault data.

Deposit Function

pub fn deposit(
    program_id: &Pubkey,
    accounts  : &[AccountInfo],
    amount    : u64
) -> ProgramResult {
    // ... (implementation details)
}

This function handles depositing SOL into a Program Derived Address (PDA). It:

  1. Extracts necessary accounts.
  2. Derives the PDA.
  3. Initializes the PDA if it's new.
  4. Updates the PDA's balance and timestamp.
  5. Transfers SOL from the user to the PDA.

Partial Withdraw Function

pub fn partial_withdraw(
    program_id: &Pubkey,
    accounts  : &[AccountInfo]
) -> ProgramResult {
    // ... (implementation details)
}

This function handles partial withdrawal from the PDA. It:

  1. Extracts necessary accounts.
  2. Derives the PDA.
  3. Checks if enough time has passed since the deposit.
  4. Calculates and transfers 1/10th of the balance to the user.
  5. Marks the PDA as "done" to prevent further withdrawals.

Each of these functions uses various Solana-specific concepts like PDAs, rent, system instructions, and more. They also handle error cases and perform necessary checks to ensure the security and correctness of the operations.

About

Build a native Solana program to create initialize an account, deposit SOL into it, and withdraw 10% of the deposited SOL at a given time from it.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published