Solana

1. Introduction to Solana 🌟

Solana is a high-performance blockchain platform designed to facilitate the development and execution of decentralized applications (dApps). It aims to address the scalability limitations of other blockchains, such as Ethereum, by introducing innovative technologies.

Key Characteristics:

  • ⚡ High throughput: Up to 65,000 transactions per second

  • ⏱️ Low latency: Block times of 400 milliseconds

  • 💰 Low transaction costs: Average cost per transaction is $0.00025

  • 🌿 Energy efficient: Uses Proof of Stake (PoS) consensus mechanism

Key Features

  • High Speed: Solana is renowned for its ability to process a large number of transactions per second (TPS), significantly outperforming other blockchains.

  • Low Fees: Due to its high throughput, transaction fees on Solana are typically lower than on other platforms.

  • Proof of History (PoH): Solana uses a unique consensus mechanism called Proof of History (PoH) to achieve high speeds and scalability. It involves creating a verifiable record of events before they are added to the blockchain.

  • Smart Contracts: Solana supports smart contracts, allowing developers to create decentralized applications.

  • Scalability: The platform is designed to handle a growing number of users and transactions without compromising performance.

2. Installation and Setup 🛠️

Install Solana CLI

MacOS & Linux

The below commands run for WSL as well.💡Install the Solana CLI | Solana Validator (solanalabs.com)

Windows

Download the highlighted folder from - https://github.com/solana-labs/solana/releases

notion image

Unzip and you should see all the .exe files

notion image

Confirm by running commands

RPC URL, Testnet, Devnet, and Mainnet

notion image

What is an RPC URL?

  • RPC (Remote Procedure Call) URLs allow applications like browsers, wallets, and users to interact with the Solana blockchain.

  • By sending requests to an RPC URL, you can query the blockchain and perform various operations.

  • How to Use RPC URLs:

Mainnet: https://api.mainnet-beta.solana.com

Devnet: https://api.devnet.solana.com

Testnet: https://api.testnet.solana.com

💡Clusters and Public RPC Endpoints | Solana

Changing RPC URLs

Use the following commands to set the appropriate RPC URL for your environment:

# Set RPC URL for Mainnet
solana config set --url https://api.mainnet-beta.solana.com

# Set RPC URL for Devnet
solana config set --url https://api.devnet.solana.com

# Set RPC URL for Testnet
solana config set --url https://api.testnet.solana.com

Solana Networks

  • Mainnet: The live Solana blockchain where real transactions occur. It’s secure and used for deploying production applications.

  • Testnet: A testing environment that mimics the mainnet but is used for testing applications before deploying them to the mainnet. It does not use real SOL.

  • Devnet: A development environment similar to the testnet but specifically for developers to experiment and test applications. You can freely request SOL from the Solana Devnet Faucet for testing purposes.

Using Devnet and Testnet

  • Airdrop SOL: On Devnet, you can use the faucet to receive free SOL for testing.

  • Local Testing: Use the Solana Test Validator to start a local validator for testing applications without relying on external networks.

solana-test-validator

Solana Explorer

  • Explorer Tool: You can view transactions, account balances, and more on the Solana blockchain using the Solana Explorer, which supports Devnet, Testnet, Mainnet, and custom RPC URLs.

3. Core Concepts 🧠

3.1 Accounts

In Solana, an account is a fundamental data structure that can hold data and SOL tokens. There are two types of accounts:

  • Data Accounts: Store program-specific data

  • SOL Accounts: Hold SOL tokens

3.2 Programs

Programs in Solana are similar to smart contracts in other blockchains. They are stateless and can be called to operate on accounts.

3.3 Transactions

Transactions in Solana are atomic, meaning they either complete entirely or fail entirely. A transaction consists of one or more instructions.

3.4 Instructions

Instructions are the basic unit of execution in Solana. Each instruction specifies a program to call, accounts to pass to the program, and data that serves as input to the program.

4. Key Features 🔑

4.1 Proof of History (PoH)

Proof of History is a novel timekeeping method for distributed systems. It creates a historical record that proves that an event has occurred at a specific moment in time.

4.2 Tower BFT

Tower BFT is Solana's implementation of Practical Byzantine Fault Tolerance (PBFT). It leverages the PoH as a reliable source of time before consensus to reduce messaging overhead and latency.

4.3 Gulf Stream

Gulf Stream is Solana's mempool-less transaction forwarding protocol. It allows for transaction caching and forwarding at the edge of the network, reducing confirmation times and the memory pressure on validators.

4.4 Sealevel

Sealevel is Solana's parallel smart contracts runtime. It allows for horizontal scaling of transaction processing across GPUs and SSDs.

5. Solana CLI Commands 🖥️

Here are some essential Solana CLI commands:

# Check your balance
solana balance

# Transfer SOL
solana transfer <RECIPIENT_ADDRESS> <AMOUNT> --allow-unfunded-recipient

# Deploy a program
solana program deploy <PROGRAM_FILEPATH>

# Get account info
solana account <ACCOUNT_ADDRESS>

# Get cluster info
solana cluster-version

These commands are crucial for interacting with the Solana blockchain, managing accounts, and deploying programs.

6. Benefits of Solana 🌈

  • 🚀 High Performance: Solana's architecture allows for incredibly high transaction throughput.

  • 💰 Low Costs: Transaction fees on Solana are very low, making it suitable for micro-transactions.

  • ⚡ Fast Finality: Transactions are confirmed quickly, providing a smooth user experience.

  • 🌿 Eco-Friendly: Solana's Proof of Stake consensus mechanism is more energy-efficient than Proof of Work.

  • 🔧 Developer-Friendly: With a growing ecosystem and developer tools, Solana is becoming increasingly accessible for builders.

This comprehensive guide should give you a solid foundation in Solana development. Remember, the best way to learn is by doing, so don't hesitate to start building your own Solana projects! Happy coding! 🚀👨‍💻👩‍💻

7. Accounts in Solana

What is an Account?

  • In Solana, an account is a data structure that includes a public-private key pair (using the ed25519 elliptic curve).

  • Types of Accounts:

  • Wallet Accounts: These accounts represent user wallets that can hold lamports (Solana’s native currency).

  • Data Accounts: These accounts store data on the blockchain and can be used for various decentralized applications.

  • Program Accounts: These are special accounts that store executable code, allowing smart contracts (known as "programs" in Solana) to run on the blockchain.

Rent on Solana

  • Purpose of Rent: To prevent the blockchain from being clogged with inactive or unnecessary data, Solana charges rent for storing data.

  • Rent Calculation: Rent is based on the storage size and the duration the account remains on the blockchain.

  • Rent Exemption: If an account maintains a balance above a certain threshold, it becomes "rent-exempt," meaning it does not incur further rent charges. The rent paid is refundable when the account is closed.

💡What is Rent on Solana and How to Calculate it | QuickNode

Efficient Storage Management

  • Incentivizing Minimal Storage: The rent model encourages users to store only the necessary data, reducing blockchain bloat.

  • Removing Inactive Accounts: Accounts that fail to pay the required rent are eventually removed from the ledger, ensuring efficient use of blockchain resources.

Calculating Rent-Exempt Threshold

  • Methods to Calculate:

  1. Solana CLI: Command-line interface tools.

  2. Solana Web3.js Library: JavaScript library for interacting with the Solana blockchain.

  3. Anchor's Space Constraint: A framework-specific approach for calculating space requirements for accounts.

8. Web2 Data Model vs. Solana Data Model

Web2 Data Model

  • Applications are typically deployed on cloud providers with backend code and data storage separated.

  • Databases: Use SQL or NoSQL databases to store user data.

  • Data Management: Adding or deleting a user involves simply adding or removing a row in the database.

notion image

Solana Data Model

  • Smart Contracts: In Web3, smart contracts are equivalent to backend applications in Web2. These are deployed on the blockchain.

  • Program Storage: On Solana, smart contracts (called "programs") are stored in executable accounts.

  • Data Storage: Unlike Ethereum, where data and smart contract code are stored together, Solana separates them:

  • Data Accounts: Store data independently from programs.

  • Executable Accounts: Store the smart contract code (programs).

notion image

Key Differences and Implications

  • User Account Management:

  • In Solana, each user requires a separate account, which adds complexity compared to simply adding a row in a Web2 database.

  • User-Paid Fees: The responsibility for creating and funding these accounts, including paying for data rent, is delegated to the user.

  • Decentralized Fees: Users pay the fees for their individual accounts, not the program itself. If an account is closed, any remaining rent is refunded to the user.

9. Token Program on Solana

notion image

Creating Tokens: Ethereum vs. Solana

  • Ethereum:

  • To create a token, you must deploy your own smart contract.

  • Ethereum provides a standard template (ERC-20), but each token requires its own contract to be deployed on the blockchain.

  • Solana:

  • Solana simplifies this process with a single, pre-deployed Token Program.

  • Instead of deploying a new contract, you only need to create a token account under this program.

  • This significantly reduces complexity and deployment costs.

Understanding Tokens

  • Tokens represent one of the primary use cases of blockchain technology, acting as digital assets or currencies that can be transferred or traded on the blockchain.

  • Examples: USDC and USDT are popular stablecoins that have found significant market adoption. These tokens do not have their own blockchain; instead, they operate as smart contracts on existing blockchains like Ethereum and Solana.

  • Why Use Existing Blockchains?

  • Tokens like USDC and USDT leverage the security and infrastructure of established blockchains such as Solana and Ethereum. This allows them to function without maintaining their own blockchain or miners.

  • The Token Program is essentially a mapping from an account to a number, representing the balance of tokens held by an account.

💡Explore various tokens and their market data on CoinMarketCap.

Solana's Token Program

  • Centralized Token Program:

  • Solana engineers recognized the importance of tokens and created a dedicated Token Program.

  • This program is pre-deployed on the Solana blockchain, simplifying token creation.

  • Mint Accounts:

  • When creating a token on Solana, you establish a mint account under the Token Program.

  • A mint account functions like a bank for your token, overseeing its supply but without executing any code. It does not run transactions or logic on its own; instead, it is responsible for managing the minting and overall supply of tokens.

  • Associated token account:

  • Associated Token Account is a token account whose address is deterministically derived using the owner's address and the mint account's address.

💡Solana program library: solana-labs/solana-program-library: A collection of Solana programs maintained by Solana Labs (github.com)

Creating a Token using CLI

Creating a Token using JavaScript

  • Check your balance in the explorer

  • Import the token in Phantom and see the balances

Equivalent code in rust/python/go

Solana has libraries similar to @solana/web3.js in Rust, Python that would let you do the same thing.In the end, they all are sending requests to an RPC server.

notion image

10. Token 22 program

  • A token program on the Solana blockchain, defining a common implementation for fungible and non-fungible tokens.

  • The Token-2022 Program, also known as Token Extensions, is a superset of the functionality provided by the Token Program.

💡https://spl.solana.com/token-2022

Create token mint
 spl-token create-token  --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
Create an associated token account
spl-token create-account 8fTM5XYRaoTJU9PLUuyakF3EypQ4RXL5HxKtiw2z9pQQ
Mint the tokens
spl-token mint 8fTM5XYRaoTJU9PLUuyakF3EypQ4RXL5HxKtiw2z9pQQ  100

Token 22 with metadata

Create a token with metadata enabled
spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --enable-metadata
Create metadata
spl-token initialize-metadata pXfZ6Hg2s78m1iSRVsdzos9TmfkqkQdv5MmQrr77ZQK 100xx 100xxx https://cdn.100xdevs.com/metadata.json
Create associated token account
 spl-token create-account pXfZ6Hg2s78m1iSRVsdzos9TmfkqkQdv5MmQrr77ZQK
Mint
 spl-token mint 1000
Check out the token in your wallet

11. Accounts

Ref - https://solana.com/docs/core/accounts

On Solana, all data is stored in what are referred to as "accounts”. The way data is organized on Solana resembles a key-value store, where each entry in the database is called an "account".

Key points

  • Accounts can store up to 10MB of data, which can consist of either executable program code or program state.

    • Programs (smart contracts) are stateless accounts that store executable code.

    • Data accounts are created by programs to store and manage program state.

  • Accounts require a rent deposit in SOL, proportional to the amount of data stored, which is fully refundable when the account is closed.

  • Every account has a program owner. Only the program that owns an account can modify its data or deduct its lamport balance. However, anyone can increase the balance.

  • Native programs are built-in programs included with the Solana runtime.

Account

Each account is identifiable by its unique address, represented as 32 bytes in the format of an Ed25519 PublicKey. You can think of the address as the unique identifier for the account.

AccountInfo

Accounts have a max size of 10MB (10 Mega Bytes) and the data stored on every account on Solana has the following structure known as the AccountInfo.

Even if you store not data, you have to store fields like executable and owner which is why you still have to have a minimum amount of SOL as rent solana rent 0

Example accounts

Program account (Owner - BPF Loader)

https://explorer.solana.com/address/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5D

12. System program

Solana contains a small handful of native programs that are part of the validator implementation and provide various core functionalities for the network.

When developing custom programs on Solana, you will commonly interact with two native programs, the System Program and the BPF Loader.

By default, all new accounts are owned by the System Program. The System Program performs several key tasks such as:

  • New Account Creation: Only the System Program can create new accounts.

  • Space Allocation: Sets the byte capacity for the data field of each account.

  • Assign Program Ownership: Once the System Program creates an account, it can reassign the designated program owner to a different program account. This is how custom programs take ownership of new accounts created by the System Program.

On Solana, a wallet is simply an account owned by the System Program. The lamport balance of the wallet is the amount of SOL owned by the account.

Using @solana/web3.js to interact with the System program

  • Create a new account with data and rent

    const { Keypair, Connection, SystemProgram, Transaction } = require('@solana/web3.js');
    
    const payer = Keypair.fromSecretKey(Uint8Array.from([222,61,190,103,38,70,4,221,24,242,44,86,66,111,102,52,87,41,83,45,166,179,184,79,208,91,20,66,142,36,147,236,30,84,33,77,227,36,159,27,27,53,27,249,230,207,30,83,42,51,3,225,70,41,44,85,54,31,198,80,45,49,208,39]));
    
    const mintAthority = payer;
    
    const connection = new Connection("<https://api.devnet.solana.com>");
    async function main() {
        const newAccount = Keypair.generate();
        const TOTAL_BYTES = 165;
        const lamports = await connection.getMinimumBalanceForRentExemption(TOTAL_BYTES);
        const transaction = new Transaction();
        transaction.add(
            SystemProgram.createAccount({
                fromPubkey: payer.publicKey,
                newAccountPubkey: newAccount.publicKey,
                lamports: lamports,
                space: TOTAL_BYTES,
                programId: SystemProgram.programId,
            }),
        );
    
        await connection.sendTransaction(transaction, [payer, newAccount]);
        console.log(`New account created at ${newAccount.publicKey.toBase58()}`);
    }
    
    main();
  • Transfer lamports from your account to another account

    const { createMint } = require('@solana/spl-token');
    const { Keypair, Connection, SystemProgram, Transaction } = require('@solana/web3.js');
    
    const payer = Keypair.fromSecretKey(Uint8Array.from([222,61,190,103,38,70,4,221,24,242,44,86,66,111,102,52,87,41,83,45,166,179,184,79,208,91,20,66,142,36,147,236,30,84,33,77,227,36,159,27,27,53,27,249,230,207,30,83,42,51,3,225,70,41,44,85,54,31,198,80,45,49,208,39]));
    
    const mintAthority = payer;
    
    const connection = new Connection("<https://api.devnet.solana.com>");
    async function main() {
        const newAccount = Keypair.generate();
        const TOTAL_BYTES = 165;
        const lamports = await connection.getMinimumBalanceForRentExemption(TOTAL_BYTES);
        const transaction = new Transaction();
        transaction.add(
            SystemProgram.transfer({
                fromPubkey: payer.publicKey,
                toPubkey: newAccount.publicKey,
                lamports,
            }),
        );
    
        await connection.sendTransaction(transaction, [payer, newAccount]);
        console.log(`Transferred to  ${newAccount.publicKey.toBase58()}`);
    }
    
    main();
  • Change the owner of an account

    const { createMint } = require('@solana/spl-token');
    const { Keypair, Connection, SystemProgram, Transaction } = require('@solana/web3.js');
    
    const payer = Keypair.fromSecretKey(Uint8Array.from([222,61,190,103,38,70,4,221,24,242,44,86,66,111,102,52,87,41,83,45,166,179,184,79,208,91,20,66,142,36,147,236,30,84,33,77,227,36,159,27,27,53,27,249,230,207,30,83,42,51,3,225,70,41,44,85,54,31,198,80,45,49,208,39]));
    
    const connection = new Connection("<https://api.devnet.solana.com>");
    async function main() {
        const newAccount = Keypair.generate();
        const owner = Keypair.generate();
        const TOTAL_BYTES = 165;
        const lamports = await connection.getMinimumBalanceForRentExemption(TOTAL_BYTES);
        const transaction = new Transaction();
        transaction.add(
            SystemProgram.createAccount({
                fromPubkey: payer.publicKey,
                newAccountPubkey: newAccount.publicKey,
                lamports: lamports,
                space: TOTAL_BYTES,
                programId: owner.publicKey,
            }),
        );
    
        await connection.sendTransaction(transaction, [payer, newAccount]);
        console.log(`New account created at ${newAccount.publicKey.toBase58()}`);
    }
    
    main();
    

13. BPF Loader Program

The BPF Loader is the program designated as the "owner" of all other programs on the network, excluding Native Programs. It is responsible for deploying, upgrading, and executing custom programs.

A program I deployed just before todays class - https://explorer.solana.com/address/8rpHNPsyEJQEJjC2waWvUXyvCkYghCZndACoXs9sNKZg?cluster=devnet

14. Authority in solana programs

In Solana programs, authorities are entities or accounts that have the right to perform certain actions or make changes within the program.

For example

Creating and revoking mint authority

  • Create a new token

spl-token create-token
  • Create an ata

spl-token create-account <token_mint_address> 
  • Try minting some tokens

spl-token mint <token_mint_address> 10000000000
  • Check if mint authority exists on explorer

  • Revoke mint authority

spl-token authorize  <token_id>  mint --disable
  • Try to mint again/check the explorer

spl-token mint <token_mint_address> 10000000000

Program derived addresses

Ref - https://solana.com/docs/core/pda

Video - https://www.youtube.com/watch?v=p0eD29d8JCM

Program Derived Addresses (PDAs) provide developers on Solana with two main use cases:

  • Deterministic Account Addresses: PDAs provide a mechanism to deterministically derive an address using a combination of optional "seeds" (predefined inputs) and a specific program ID.

  • Enable Program Signing: The Solana runtime enables programs to "sign" for PDAs which are derived from its program ID.

Properties

  • PDAs are addresses derived deterministically using

    • a combination of user-defined seeds

    • a bump seed

    • and a program's ID.

  • PDAs are addresses that fall off the Ed25519 curve and have no corresponding private key.

  • Solana programs can programmatically "sign" for PDAs that are derived using its program ID.

  • Deriving a PDA does not automatically create an on-chain account.

  • An account using a PDA as its address must be explicitly created through a dedicated instruction within a Solana program.

Find the associated token account for a user and a mint

const { PublicKey } = require('@solana/web3.js');
const { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } = require('@solana/spl-token');

// Replace these with your actual values
const userAddress = new PublicKey('5gjLjKtBhDxWL4nwGKprThQwyzzNZ7XNAVFcEtw3rD4i');
const tokenMintAddress = new PublicKey('6NeR2StEEb6CP75Gsd7ydbiAkabdriMdixPmC2U9hcJs');

// Derive the associated token address
const getAssociatedTokenAddress = (mintAddress, ownerAddress) => {
    return PublicKey.findProgramAddressSync(
        [
            ownerAddress.toBuffer(),
            TOKEN_PROGRAM_ID.toBuffer(),
            mintAddress.toBuffer(),
        ],
        ASSOCIATED_TOKEN_PROGRAM_ID
    );
};

const [associatedTokenAddress, bump] = getAssociatedTokenAddress(tokenMintAddress, userAddress);
console.log(`Associated Token Address: ${associatedTokenAddress.toBase58()}, bump: ${bump}`);

Last updated

Was this helpful?