Bedah Solana Web3: Panduan Lengkap Ngoding dApps dan Smart Contract dari Nol (Pakai Anchor, Bro!)

ikramlink Maret 26, 2026
Bedah Solana Web3: Panduan Lengkap Ngoding dApps dan Smart Contract dari Nol (Pakai Anchor, Bro!)

Halo Sobat Coder dan Web3 Enthusiast!

Gimana kabar kodingan hari ini? Semoga lancar jaya ya! Pernah nggak sih kepikiran buat terjun langsung ke dunia Web3, khususnya di ekosistem Solana yang lagi nge-hype banget ini? Jujur aja, dulu pas awal-awal kenalan sama Web3, rasanya kayak ngeliat alien ngomong bahasa Sanskrit. Bingung banget mau mulai dari mana. Tapi, setelah ngoprek sana-sini, ternyata nggak seseram itu kok, apalagi kalau kita pakai tools yang tepat.

Nah, di artikel kali ini, gue mau ajak kalian semua buat ngebedah tuntas gimana caranya membangun dApps (Decentralized Applications) dan Smart Contract (yang di Solana kita sebut 'Program') di jaringan Solana, bener-bener dari nol! Kita bakal pakai Framework Anchor yang jadi penyelamat para developer Solana. Jadi, siapin kopi atau teh favorit kalian, buka VS Code, dan mari kita mulai petualangan koding di Solana!

Kenapa Harus Solana, Bro?

Dari sekian banyak blockchain di luar sana, kenapa Solana? Ini pertanyaan krusial. Buat gue pribadi, ada beberapa alasan kuat kenapa Solana jadi pilihan menarik:

  • Kecepatan & Skalabilitas Gila-gilaan: Solana bisa memproses ribuan transaksi per detik (TPS), jauh banget dibanding Ethereum yang masih di puluhan TPS. Ini penting banget buat dApps yang butuh performa tinggi kayak game atau DeFi.
  • Biaya Transaksi (Gas Fee) Murah Banget: Beneran, murahnya keterlaluan! Kalian bisa bayar gas fee cuma dalam hitungan sen dolar. Ini bikin pengalaman user jauh lebih baik karena nggak perlu khawatir sama biaya transaksi yang tiba-tiba melambung tinggi.
  • Ekosistem yang Berkembang Pesat: Komunitas developernya makin gede, banyak proyek inovatif muncul, dan tools-nya juga makin matang. Ini berarti banyak referensi dan support kalau kalian mentok.
  • Rust-Powered: Smart contract di Solana ditulis pakai Rust, bahasa pemrograman yang dikenal super aman dan performatif. Meskipun kurva belajarnya agak terjal di awal, tapi benefits-nya sepadan banget.

Memang sih, dulu Solana sempat ada isu-isu outage. Tapi percaya deh, tim di belakangnya terus berbenah dan jaringan mereka makin stabil. Ibarat software versi beta, pasti ada bug di awal, tapi terus di-improve. Optimisme gue pribadi sih tinggi banget sama masa depan Solana!

Persiapan Tempur: Tools yang Wajib Ada

Sebelum kita terjun ke kodingan, kita perlu siapin amunisi dulu. Ini daftar tools yang wajib kalian install:

1. Rust & Cargo

Rust adalah bahasa utama untuk menulis program Solana. Cargo itu package manager-nya Rust. Gampang kok install-nya:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

Ikuti aja instruksinya. Setelah itu, cek versi Rust kalian dengan rustc --version dan Cargo dengan cargo --version.

2. Node.js & npm/Yarn

Kita butuh Node.js buat frontend dApp kita dan juga beberapa tools Solana. npm (Node Package Manager) atau Yarn buat manage package JavaScript kita.

# Install Node.js (disarankan pakai nvm atau versi LTS)
# Kalau udah ada, tinggal update aja.
node -v
npm -v

3. Solana CLI (Command Line Interface)

Ini adalah toolkit utama kita buat interaksi sama jaringan Solana, kayak generate keypair, deploy program, cek saldo, dll.

sh -c "$(curl -sSfL https://release.solana.com/v1.17.18/install)"
export PATH="/root/.local/share/solana/install/active_release/bin:$PATH"
# Ganti v1.17.18 dengan versi terbaru kalau sudah ada rilis baru
solana --version

Setelah install, konfigurasikan Solana CLI kita ke devnet dulu buat testing:

solana config set --url devnet
solana config get

Kita juga perlu keypair. Ini semacam identitas kita di blockchain Solana. Buat yang baru, generate aja:

solana-keygen new --outfile ~/.config/solana/id.json

Simpan baik-baik passphrase-nya ya!

4. Anchor CLI

Nah, ini dia hero kita! Anchor Framework adalah framework yang bikin pengembangan smart contract di Solana jadi jauh lebih mudah. Dia menyediakan boilerplate code, generate IDL (Interface Definition Language), dan bikin testing jadi gampang. Singkatnya, Anchor itu kayak "Truffle/Hardhat"-nya Solana.

npm install -g @project-serum/anchor-cli
anchor --version

Oke, semua senjata udah siap! Sekarang mari kita pahami sedikit konsep dasar di Solana.

Memahami Arsitektur Solana (Basic Banget!)

Solana itu beda banget sama Ethereum (EVM-based). Kalau di Ethereum, smart contract punya "storage" sendiri. Di Solana, konsepnya sedikit berbeda:

  • Programs (Smart Contracts): Ini adalah kode yang dieksekusi di blockchain. Mereka itu stateless, artinya mereka nggak menyimpan data secara langsung. Mereka cuma punya logika bisnis.
  • Accounts: Ini adalah tempat data disimpan di Solana. Semua data, mulai dari saldo SOL kalian, NFT, sampai data custom dApp, disimpan di dalam "Accounts". Program berinteraksi dengan Accounts ini untuk membaca dan menulis data. Bayangin Accounts itu kayak database, dan Programs itu kayak API yang interaksi sama database itu.

Konsep ini sering bikin pusing di awal, tapi justru ini yang bikin Solana efisien. Program bisa fokus sama logika, data diurus sama Accounts yang terpisah. Anchor bakal bantu kita banget untuk ngelola Accounts ini secara gampang.

Memulai Proyek Anchor: Siap Ngoding!

Oke, tanpa basa-basi lagi, kita langsung aja bikin proyek Anchor pertama kita. Buka terminal dan ketik:

anchor init my-first-solana-dapp
cd my-first-solana-dapp

Perintah ini akan membuat struktur proyek standar Anchor. Kalau kita intip isinya, ada beberapa folder penting:

  • programs/: Di sinilah file Rust smart contract kita akan berada.
  • tests/: Untuk unit dan integrasi tes program kita (pakai TypeScript/JavaScript).
  • app/: Biasanya untuk frontend dApp kita (optional, bisa juga di luar).
  • Anchor.toml: File konfigurasi proyek Anchor.

Mari kita buka folder programs/my-first-solana-dapp/src/lib.rs. Di sana sudah ada contoh program "Hello, World!" sederhana. Kita akan modifikasi sedikit untuk membuat program counter.

Membangun Program Counter Sederhana

Kita akan bikin program yang bisa menyimpan angka dan menaikkan (increment) angkanya. Ini dia kodenya:

use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"); // Ganti dengan Program ID yang nanti di-generate Anchor

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

    pub fn initialize(ctx: Context) -> Result<()> {
        let base_account = &mut ctx.accounts.base_account;
        base_account.count = 0;
        Ok(())
    }

    pub fn increment(ctx: Context) -> Result<()> {
        let base_account = &mut ctx.accounts.base_account;
        base_account.count += 1;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8 + 8)] // 8 byte untuk Discriminator, 8 byte untuk u64 count
    pub base_account: Account<'info, BaseAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub base_account: Account<'info, BaseAccount>,
}

#[account]
pub struct BaseAccount {
    pub count: u64,
}

Mari kita bedah sedikit kode di atas:

  • declare_id!: Ini adalah Program ID kita. Nanti akan di-generate otomatis saat deploy pertama kali.
  • #[program]: Ini makro Anchor yang menandakan blok kode ini adalah program Solana kita. Di dalamnya ada fungsi initialize (buat inisialisasi counter) dan increment (buat nambah counter).
  • Context<Initialize>: Ini adalah parameter yang membawa semua Accounts yang dibutuhkan oleh fungsi kita.
  • #[derive(Accounts)]: Ini makro Anchor untuk mendefinisikan struktur Accounts yang akan diakses oleh Program.
    • Initialize: Membutuhkan base_account (tempat data counter kita) yang diinisialisasi (`init`), dibayar oleh user (`payer`), dan berukuran space 16 byte (8 byte Anchor discriminator + 8 byte u64).
    • Increment: Hanya butuh base_account yang bisa dimodifikasi (`mut`).
  • #[account]: Ini makro untuk mendefinisikan struktur data kita, dalam hal ini BaseAccount yang punya field count bertipe u64.

Gimana, agak pusing? Tenang, itu normal. Anchor ini memang sedikit "magical" di awal, tapi dia sangat membantu ngurangi boilerplate Rust yang rumit di Solana.

Kompilasi dan Deploy Program

Setelah kodingan Rust kita selesai, saatnya kompilasi dan deploy! Jalankan perintah ini di root folder proyek:

anchor build

Kalau berhasil, kalian akan melihat output yang menunjukkan kompilasi sukses. Sekarang, saatnya deploy ke devnet:

anchor deploy

Perintah anchor deploy akan:

  1. Mendeploy program kita ke devnet.
  2. Meng-update file Anchor.toml dengan Program ID baru.
  3. Men-generate file IDL (Interface Definition Language) di target/idl/my_first_solana_dapp.json. File IDL ini penting banget karena akan dipakai oleh frontend kita untuk berinteraksi dengan program.

Catat Program ID kalian yang ada di Anchor.toml dan juga di output anchor deploy. Itu adalah alamat unik program kita di jaringan Solana.

Membangun Frontend dApp (Interaksi dengan Program)

Oke, program kita sudah hidup di devnet. Sekarang, gimana caranya kita interaksi sama program itu dari website? Di sinilah peran frontend dApp.

Persiapan Frontend

Kita bisa pakai React, Vue, atau JavaScript biasa. Untuk contoh ini, kita pakai React saja yang populer. Masuk ke folder app/ (atau buat folder baru di root proyek) dan inisialisasi proyek React:

# Di root proyek (my-first-solana-dapp)
npx create-react-app app
cd app
npm install @solana/web3.js @project-serum/anchor --save

Selanjutnya, kita perlu salin file IDL kita dari target/idl/my_first_solana_dapp.json ke folder app/src. Ini penting agar frontend tahu "API" program kita.

cp ../target/idl/my_first_solana_dapp.json src/my_first_solana_dapp.json

Kode Frontend (React)

Mari kita buat file app/src/App.js menjadi seperti ini (ini versi sederhananya ya):

import React, { useEffect, useState } from 'react';
import { Connection, PublicKey, clusterApiUrl } from '@solana/web3.js';
import { Program, AnchorProvider, web3, utils } from '@project-serum/anchor';
import idl from './my_first_solana_dapp.json';

const programID = new PublicKey(idl.metadata.address);
const network = clusterApiUrl('devnet');
const opts = {
  preflightCommitment: "processed"
};

const App = () => {
  const [walletAddress, setWalletAddress] = useState(null);
  const [baseAccount, setBaseAccount] = useState(null);

  const getProvider = () => {
    const connection = new Connection(network, opts.preflightCommitment);
    const provider = new AnchorProvider(
      connection,
      window.solana, // Mengasumsikan Phantom Wallet terinstall
      opts.preflightCommitment,
    );
    return provider;
  };

  const checkIfWalletIsConnected = async () => {
    try {
      const { solana } = window;
      if (solana) {
        if (solana.isPhantom) {
          console.log('Phantom wallet found!');
          const response = await solana.connect({ onlyIfTrusted: true });
          console.log(
            'Connected with Public Key:',
            response.publicKey.toString()
          );
          setWalletAddress(response.publicKey.toString());
        }
      } else {
        alert('Solana object not found! Get a Phantom Wallet 👻');
      }
    } catch (error) {
      console.error(error);
    }
  };

  const connectWallet = async () => {
    const { solana } = window;
    if (solana) {
      const response = await solana.connect();
      console.log('Connected with Public Key:', response.publicKey.toString());
      setWalletAddress(response.publicKey.toString());
    }
  };

  const getBaseAccount = async () => {
    const provider = getProvider();
    const program = new Program(idl, programID, provider);
    const [accountPublicKey] = PublicKey.findProgramAddressSync(
      [utils.bytes.utf8.encode("base_account")], // Seed yang sama saat inisialisasi
      programID
    );
    try {
      const account = await program.account.baseAccount.fetch(accountPublicKey);
      setBaseAccount(account);
      console.log("Account data: ", account);
    } catch (error) {
      console.log("Error fetching base account:", error);
      setBaseAccount(null);
    }
  };

  const initializeAccount = async () => {
    try {
      const provider = getProvider();
      const program = new Program(idl, programID, provider);
      const [accountPublicKey] = PublicKey.findProgramAddressSync(
        [utils.bytes.utf8.encode("base_account")],
        programID
      );
      
      await program.methods.initialize()
        .accounts({
          baseAccount: accountPublicKey,
          user: provider.wallet.publicKey,
          systemProgram: web3.SystemProgram.programId,
        })
        .rpc();
      console.log("Base account initialized!");
      await getBaseAccount();
    } catch (error) {
      console.error("Error initializing account:", error);
    }
  };

  const incrementCount = async () => {
    try {
      const provider = getProvider();
      const program = new Program(idl, programID, provider);
      const [accountPublicKey] = PublicKey.findProgramAddressSync(
        [utils.bytes.utf8.encode("base_account")],
        programID
      );

      await program.methods.increment()
        .accounts({
          baseAccount: accountPublicKey,
        })
        .rpc();
      console.log("Count incremented!");
      await getBaseAccount();
    } catch (error) {
      console.error("Error incrementing count:", error);
    }
  };

  useEffect(() => {
    const onLoad = async () => {
      await checkIfWalletIsConnected();
    };
    window.addEventListener('load', onLoad);
    return () => window.removeEventListener('load', onLoad);
  }, []);

  useEffect(() => {
    if (walletAddress) {
      getBaseAccount();
    }
  }, [walletAddress]);

  const renderNotConnectedContainer = () => (
    
  );

  const renderConnectedContainer = () => (
    

Wallet connected: {walletAddress}

{!baseAccount ? ( ) : (

Current Count: {baseAccount.count.toString()}

)}
); return (

My Solana Counter dApp

Build with Anchor

{!walletAddress && renderNotConnectedContainer()} {walletAddress && renderConnectedContainer()}
); }; export default App;

Beberapa poin penting di kode frontend di atas:

  • Kita menggunakan @solana/web3.js untuk koneksi ke jaringan Solana dan @project-serum/anchor untuk interaksi dengan program Anchor kita.
  • idl diimport untuk mengetahui struktur program dan fungsinya.
  • getProvider(): Fungsi ini membuat koneksi ke Solana dan menginisialisasi provider Anchor. Kita mengasumsikan user punya Phantom Wallet terinstal.
  • checkIfWalletIsConnected() & connectWallet(): Untuk mendeteksi dan menghubungkan Phantom Wallet.
  • PublicKey.findProgramAddressSync(): Ini kunci! Di Solana, kita sering menggunakan PDA (Program Derived Address) untuk membuat account yang bisa dikontrol oleh program. Di sini kita membuat PDA untuk base_account kita. Seed "base_account" harus sama persis dengan yang kita pakai di Rust kalau kita pakai `init` di `#[account]` Anchor.
  • program.methods.initialize().accounts({...}).rpc(): Ini cara kita memanggil fungsi initialize dari program Solana kita. Kita perlu provide semua accounts yang dibutuhkan oleh fungsi tersebut (sesuai definisi #[derive(Accounts)] di Rust).
  • program.account.baseAccount.fetch(accountPublicKey): Untuk mengambil data dari account baseAccount.

Jangan lupa tambahkan CSS sederhana di app/src/index.css agar tampilannya tidak terlalu polos:

.App {
  font-family: sans-serif;
  text-align: center;
  margin-top: 50px;
}

.cta-button {
  background-color: #6a0dad; /* Purple */
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 16px;
  margin: 10px;
}

.cta-button:hover {
  background-color: #4b0082; /* Darker Purple */
}

.header {
  font-size: 3em;
  font-weight: bold;
  color: #6a0dad;
}

.sub-text {
  font-size: 1.2em;
  color: #333;
}

Jalankan dApp kalian:

cd app
npm start

Sekarang kalian harusnya bisa melihat dApp kalian di browser. Connect Phantom Wallet, inisialisasi account, dan coba deh klik tombol "Increment Count"! Setiap klik akan mengirim transaksi ke Solana devnet dan memperbarui nilai counter di blockchain.

Keren banget kan? Dari nol sampai punya dApp interaktif yang ngobrol sama smart contract di Solana!

Tips Tambahan & Best Practices

  • Keamanan adalah Prioritas: Smart contract itu nggak bisa diubah setelah deploy. Jadi, pastikan kodingan kalian aman. Lakukan audit, pakai unit test, dan jangan pernah anggap remeh security. Bug di smart contract bisa fatal!
  • Testing Itu Wajib: Anchor punya tool testing yang bagus banget. Manfaatkan itu buat nulis unit test dan integrasi test untuk program kalian. Ini bisa mencegah bug dan memastikan program berjalan sesuai ekspektasi.
  • Pahami Konsep Solana: Meskipun Anchor bikin gampang, tetap penting buat pahamin konsep dasar Solana (Accounts, PDAs, rent, fees, CPI). Ini akan membantu kalian debugging dan mengoptimalkan program.
  • Join Komunitas: Gabung di Discord Solana atau Anchor. Banyak developer yang siap bantu dan sharing ilmu di sana.

Penutup: Ayo Ngoprek Terus!

Gimana, bro dan sis? Lumayan panjang juga perjalanan kita dari install tools sampai deploy dApp di Solana. Semoga panduan ini bisa jadi batu loncatan kalian buat eksplorasi lebih jauh di dunia Web3, khususnya di ekosistem Solana yang super dinamis ini.

Ingat, belajar coding itu bukan cuma tentang ngikutin tutorial, tapi juga tentang eksplorasi, trial and error, dan nggak takut bikin kesalahan. Terus ngoprek, terus belajar, dan jangan pernah ragu buat bikin sesuatu yang gila di blockchain!

Kalau ada pertanyaan atau mau sharing pengalaman ngoding di Solana, jangan sungkan tinggalkan komentar di bawah ya! Sampai jumpa di artikel berikutnya, dan selamat ngoding!