Thursday

19-06-2025 Vol 19

💸 Step-by-Step Guide: Building a Split Payment DApp (for Beginners)

💸 Panduan Langkah Demi Langkah: Membuat DApp Pembayaran Terpisah (Untuk Pemula)

Selamat datang! Dalam panduan ini, kita akan menyelami dunia pengembangan aplikasi terdesentralisasi (DApp) dengan membangun DApp pembayaran terpisah yang sederhana namun kuat. Apakah Anda seorang pengembang pemula, seorang penggemar blockchain, atau sekadar ingin tahu tentang Web3, tutorial ini akan membantu Anda memahami dasar-dasarnya dan memulai.

Mengapa Membangun DApp Pembayaran Terpisah?

DApp pembayaran terpisah memungkinkan Anda dan sekelompok orang untuk berbagi biaya secara otomatis dan transparan. Bayangkan Anda pergi makan malam dengan teman-teman dan ingin membagi tagihan secara merata. Alih-alih mengandalkan perhitungan yang rumit dan transfer manual, DApp dapat secara otomatis mendistribusikan pembayaran sesuai dengan aturan yang telah ditentukan. Ini hanyalah salah satu contoh dari banyak kasus penggunaan potensial. DApp pembayaran terpisah berguna untuk:

  • Berbagi sewa rumah
  • Mengumpulkan dana untuk tujuan amal
  • Membagi biaya proyek tim
  • Mengelola pengeluaran grup

Apa yang Akan Anda Pelajari?

Dalam panduan ini, Anda akan belajar:

  1. Dasar-dasar teknologi blockchain dan Ethereum.
  2. Cara menyiapkan lingkungan pengembangan untuk DApp.
  3. Cara menulis dan menerapkan smart contract menggunakan Solidity.
  4. Cara berinteraksi dengan smart contract dari frontend menggunakan JavaScript dan library Web3.js.
  5. Cara membuat antarmuka pengguna sederhana untuk DApp Anda.

Prasyarat

Sebelum kita mulai, pastikan Anda memiliki hal berikut:

  1. Pemahaman Dasar JavaScript: Pengetahuan tentang variabel, fungsi, dan konsep pemrograman dasar lainnya diperlukan.
  2. Node.js dan npm (Node Package Manager): Ini akan digunakan untuk mengelola dependensi proyek kita. Anda dapat mengunduh dan menginstalnya dari https://nodejs.org/.
  3. Metamask: Dompet cryptocurrency yang akan kita gunakan untuk berinteraksi dengan blockchain Ethereum. Anda dapat mengunduhnya sebagai ekstensi browser dari https://metamask.io/.
  4. Ganache: Blockchain pribadi yang kita gunakan untuk mengembangkan dan menguji DApp kita secara lokal. Anda dapat mengunduhnya dari https://www.trufflesuite.com/ganache.
  5. Truffle: Framework pengembangan untuk Ethereum yang akan membantu kita menyusun dan mengelola proyek kita. Kita akan menginstalnya di bagian selanjutnya.

Langkah 1: Menyiapkan Lingkungan Pengembangan Anda

Kita akan memulai dengan menyiapkan lingkungan pengembangan kita. Ini melibatkan instalasi Truffle, Ganache, dan menyiapkan struktur proyek.

1. Instal Truffle

Buka terminal atau command prompt Anda dan jalankan perintah berikut untuk menginstal Truffle secara global:

npm install -g truffle

Ini akan menginstal Truffle di sistem Anda, memungkinkan Anda untuk menggunakan perintah Truffle dari mana saja.

2. Instal Ganache

Unduh dan instal Ganache dari https://www.trufflesuite.com/ganache. Setelah diinstal, buka Ganache. Ini akan memulai blockchain Ethereum pribadi yang akan kita gunakan untuk pengembangan.

3. Membuat Proyek Truffle

Buat direktori baru untuk proyek Anda dan navigasikan ke direktori tersebut di terminal Anda:

mkdir split-payment-dapp
cd split-payment-dapp

Selanjutnya, inisialisasi proyek Truffle:

truffle init

Ini akan membuat struktur proyek dasar dengan direktori untuk kontrak (contracts/), migrasi (migrations/), dan pengujian (test/).

Langkah 2: Menulis Smart Contract dengan Solidity

Sekarang kita akan menulis smart contract yang akan mengatur logika DApp pembayaran terpisah kita. Smart contract ditulis dalam bahasa Solidity.

1. Membuat Kontrak SplitPayment

Di direktori contracts/, buat file baru bernama SplitPayment.sol. Buka file tersebut di editor kode Anda dan tambahkan kode berikut:

pragma solidity ^0.8.0;

contract SplitPayment {
    address payable[] public recipients;
    address payable public owner;

    constructor(address payable[] memory _recipients) {
        require(_recipients.length > 0, "Recipients list cannot be empty.");
        recipients = _recipients;
        owner = payable(msg.sender);
    }

    function splitPayment() public payable {
        require(msg.value > 0, "Payment amount must be greater than zero.");
        uint256 amountPerRecipient = msg.value / recipients.length;
        uint256 remainingAmount = msg.value % recipients.length;

        for (uint256 i = 0; i < recipients.length; i++) {
            recipients[i].transfer(amountPerRecipient);
        }

        // Kembalikan sisa dana ke pemilik
        if (remainingAmount > 0) {
            owner.transfer(remainingAmount);
        }
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Only the owner can call this function.");
        _;
    }

    function withdrawRemainingBalance() public onlyOwner {
        payable(owner).transfer(address(this).balance);
    }
}

2. Penjelasan Kode Kontrak

  • pragma solidity ^0.8.0;: Menentukan versi Solidity yang digunakan untuk kontrak.
  • address payable[] public recipients;: Array alamat penerima pembayaran. Kata kunci public berarti kita dapat mengakses array ini dari luar kontrak.
  • address payable public owner;: Alamat pemilik kontrak. Hanya pemilik yang dapat menarik sisa dana.
  • constructor(address payable[] memory _recipients): Fungsi konstruktor yang dipanggil saat kontrak diterapkan. Ini membutuhkan array alamat penerima sebagai input.
  • splitPayment() public payable: Fungsi utama yang membagi pembayaran di antara penerima. Kata kunci payable berarti fungsi ini dapat menerima ETH.
  • require(msg.value > 0, "Payment amount must be greater than zero.");: Memastikan bahwa jumlah pembayaran lebih besar dari nol.
  • uint256 amountPerRecipient = msg.value / recipients.length;: Menghitung jumlah yang diterima setiap penerima.
  • recipients[i].transfer(amountPerRecipient);: Mentransfer jumlah yang dihitung ke setiap penerima.
  • getBalance() public view returns (uint256): Fungsi untuk mendapatkan saldo kontrak. Kata kunci view berarti fungsi ini tidak memodifikasi status kontrak.
  • onlyOwner(): Modifier yang memastikan bahwa hanya pemilik yang dapat memanggil fungsi tertentu.
  • withdrawRemainingBalance() public onlyOwner: Fungsi untuk menarik sisa saldo kontrak. Hanya pemilik yang dapat memanggil fungsi ini.

Langkah 3: Menerapkan Kontrak

Sekarang kita perlu menerapkan smart contract kita ke blockchain. Kita akan menggunakan Ganache untuk blockchain lokal kita.

1. Membuat File Migrasi

Di direktori migrations/, buat file baru bernama 2_deploy_split_payment.js. Buka file tersebut di editor kode Anda dan tambahkan kode berikut:

const SplitPayment = artifacts.require("SplitPayment");

module.exports = async function (deployer, network, accounts) {
  // Ganti alamat ini dengan alamat yang Anda kendalikan di Ganache.
  // Pastikan untuk menggunakan alamat dengan saldo ETH yang cukup.
  const recipients = [
    accounts[1], // Penerima 1
    accounts[2], // Penerima 2
    accounts[3], // Penerima 3
  ];

  await deployer.deploy(SplitPayment, recipients);
};

Pastikan untuk mengganti accounts[1], accounts[2], dan accounts[3] dengan alamat yang valid dari akun Ganache Anda. Anda dapat menemukan alamat ini di antarmuka Ganache.

2. Melakukan Migrasi

Buka terminal Anda dan jalankan perintah berikut untuk melakukan migrasi:

truffle migrate

Ini akan mengkompilasi dan menerapkan smart contract Anda ke blockchain Ganache. Anda akan melihat output di terminal yang menunjukkan keberhasilan penerapan.

Langkah 4: Berinteraksi dengan Kontrak Menggunakan Web3.js

Sekarang setelah kontrak kita diterapkan, kita dapat berinteraksi dengannya menggunakan Web3.js. Web3.js adalah library JavaScript yang memungkinkan kita untuk berinteraksi dengan blockchain Ethereum.

1. Menginstal Web3.js

Di terminal Anda, jalankan perintah berikut untuk menginstal Web3.js:

npm install web3

2. Membuat File JavaScript untuk Interaksi

Buat file baru bernama app.js di direktori proyek Anda. Buka file tersebut di editor kode Anda dan tambahkan kode berikut:

const Web3 = require('web3');

// Sesuaikan dengan alamat dan ABI kontrak Anda
const contractAddress = 'YOUR_CONTRACT_ADDRESS'; // Ganti dengan alamat kontrak Anda
const contractABI = [
	{
		"inputs": [
			{
				"internalType": "address payable[]",
				"name": "_recipients",
				"type": "address payable[]"
			}
		],
		"stateMutability": "nonpayable",
		"type": "constructor"
	},
	{
		"stateMutability": "payable",
		"type": "fallback"
	},
	{
		"inputs": [],
		"name": "getBalance",
		"outputs": [
			{
				"internalType": "uint256",
				"name": "",
				"type": "uint256"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "owner",
		"outputs": [
			{
				"internalType": "address payable",
				"name": "",
				"type": "address"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "recipients",
		"outputs": [
			{
				"internalType": "address payable[]",
				"name": "",
				"type": "address payable[]"
			}
		],
		"stateMutability": "view",
		"type": "function"
	},
	{
		"inputs": [],
		"name": "splitPayment",
		"outputs": [],
		"stateMutability": "payable",
		"type": "function"
	},
	{
		"stateMutability": "payable",
		"type": "receive"
	},
	{
		"inputs": [],
		"name": "withdrawRemainingBalance",
		"outputs": [],
		"stateMutability": "nonpayable",
		"type": "function"
	}
]; // Ganti dengan ABI kontrak Anda

// Inisialisasi Web3 dengan penyedia Ganache
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:7545'));

// Membuat instance kontrak
const splitPaymentContract = new web3.eth.Contract(contractABI, contractAddress);

// Fungsi untuk membagi pembayaran
async function makePayment(amountInEther) {
  // Mendapatkan akun dari Metamask
  const accounts = await web3.eth.getAccounts();
  const senderAddress = accounts[0]; // Alamat akun Metamask Anda

  // Mengonversi amountInEther ke Wei
  const amountInWei = web3.utils.toWei(amountInEther, 'ether');

  // Melakukan panggilan ke fungsi splitPayment
  try {
    await splitPaymentContract.methods.splitPayment().send({
      from: senderAddress,
      value: amountInWei,
      gas: 3000000 // Sesuaikan gas sesuai kebutuhan
    });
    console.log('Payment successful!');
  } catch (error) {
    console.error('Payment failed:', error);
  }
}

// Fungsi untuk mendapatkan saldo kontrak
async function getContractBalance() {
  try {
    const balanceInWei = await splitPaymentContract.methods.getBalance().call();
    const balanceInEther = web3.utils.fromWei(balanceInWei, 'ether');
    console.log('Contract balance:', balanceInEther, 'ETH');
  } catch (error) {
    console.error('Failed to get contract balance:', error);
  }
}

// Contoh penggunaan
async function runExample() {
  await getContractBalance();
  await makePayment('0.01'); // Mengirim 0.01 ETH
  await getContractBalance();
}

runExample();

Pastikan untuk mengganti YOUR_CONTRACT_ADDRESS dengan alamat kontrak yang Anda dapatkan setelah melakukan migrasi. Anda juga perlu mengganti contractABI dengan ABI kontrak Anda. Anda dapat menemukan ABI di file SplitPayment.json di direktori build/contracts setelah melakukan migrasi.

3. Menjalankan File JavaScript

Buka terminal Anda dan jalankan perintah berikut untuk menjalankan file JavaScript:

node app.js

Pastikan Metamask Anda terhubung ke jaringan Ganache dan Anda memiliki akun dengan saldo ETH yang cukup. Anda akan melihat output di terminal yang menunjukkan keberhasilan atau kegagalan pembayaran dan saldo kontrak.

Langkah 5: Membuat Frontend Sederhana (Opsional)

Kita dapat membuat frontend sederhana menggunakan HTML, CSS, dan JavaScript untuk berinteraksi dengan DApp kita. Ini adalah langkah opsional, tetapi akan membuat DApp kita lebih mudah digunakan.

1. Membuat File HTML

Buat file baru bernama index.html di direktori proyek Anda. Buka file tersebut di editor kode Anda dan tambahkan kode berikut:

<!DOCTYPE html>
<html>
<head>
  <title>Split Payment DApp</title>
  <script src="https://cdn.jsdelivr.net/npm/web3@1.3.4/dist/web3.min.js"></script>
  <style>
    body {
      font-family: sans-serif;
      margin: 20px;
    }
    button {
      padding: 10px 20px;
      background-color: #4CAF50;
      color: white;
      border: none;
      cursor: pointer;
      margin-top: 10px;
    }
    input {
      padding: 5px;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <h1>Split Payment DApp</h1>

  <label for="paymentAmount">Payment Amount (ETH):</label><br>
  <input type="number" id="paymentAmount" placeholder="Enter amount in ETH"><br>
  <button onclick="makePayment()">Make Payment</button><br>

  <button onclick="getContractBalance()">Get Contract Balance</button><br>
  <p id="contractBalance"></p>

  <script>
    // Sesuaikan dengan alamat dan ABI kontrak Anda
    const contractAddress = 'YOUR_CONTRACT_ADDRESS'; // Ganti dengan alamat kontrak Anda
    const contractABI = [
    	{
    		"inputs": [
    			{
    				"internalType": "address payable[]",
    				"name": "_recipients",
    				"type": "address payable[]"
    			}
    		],
    		"stateMutability": "nonpayable",
    		"type": "constructor"
    	},
    	{
    		"stateMutability": "payable",
    		"type": "fallback"
    	},
    	{
    		"inputs": [],
    		"name": "getBalance",
    		"outputs": [
    			{
    				"internalType": "uint256",
    				"name": "",
    				"type": "uint256"
    			}
    		],
    		"stateMutability": "view",
    		"type": "function"
    	},
    	{
    		"inputs": [],
    		"name": "owner",
    		"outputs": [
    			{
    				"internalType": "address payable",
    				"name": "",
    				"type": "address"
    			}
    		],
    		"stateMutability": "view",
    		"type": "function"
    	},
    	{
    		"inputs": [],
    		"name": "recipients",
    		"outputs": [
    			{
    				"internalType": "address payable[]",
    				"name": "",
    				"type": "address payable[]"
    			}
    		],
    		"stateMutability": "view",
    		"type": "function"
    	},
    	{
    		"inputs": [],
    		"name": "splitPayment",
    		"outputs": [],
    		"stateMutability": "payable",
    		"type": "function"
    	},
    	{
    		"stateMutability": "payable",
    		"type": "receive"
    	},
    	{
    		"inputs": [],
    		"name": "withdrawRemainingBalance",
    		"outputs": [],
    		"stateMutability": "nonpayable",
    		"type": "function"
    	}
    ]; // Ganti dengan ABI kontrak Anda

    let web3;
    let splitPaymentContract;

    async function init() {
      // Memeriksa apakah Metamask terinstal
      if (typeof window.ethereum !== 'undefined') {
        // Meminta akses akun
        try {
          await window.ethereum.request({ method: 'eth_requestAccounts' });
          web3 = new Web3(window.ethereum);

          // Membuat instance kontrak
          splitPaymentContract = new web3.eth.Contract(contractABI, contractAddress);

          console.log('Web3 initialized.');
        } catch (error) {
          console.error('User denied account access:', error);
        }
      } else {
        console.error('Metamask not detected. Please install Metamask.');
      }
    }

    // Fungsi untuk membagi pembayaran
    async function makePayment() {
      const amountInEther = document.getElementById('paymentAmount').value;

      if (!amountInEther) {
        alert('Please enter a payment amount.');
        return;
      }

      // Mengonversi amountInEther ke Wei
      const amountInWei = web3.utils.toWei(amountInEther, 'ether');

      // Mendapatkan akun dari Metamask
      const accounts = await web3.eth.getAccounts();
      const senderAddress = accounts[0]; // Alamat akun Metamask Anda

      // Melakukan panggilan ke fungsi splitPayment
      try {
        await splitPaymentContract.methods.splitPayment().send({
          from: senderAddress,
          value: amountInWei,
          gas: 3000000 // Sesuaikan gas sesuai kebutuhan
        });
        alert('Payment successful!');
      } catch (error) {
        console.error('Payment failed:', error);
        alert('Payment failed. See console for details.');
      }
    }

    // Fungsi untuk mendapatkan saldo kontrak
    async function getContractBalance() {
      try {
        const balanceInWei = await splitPaymentContract.methods.getBalance().call();
        const balanceInEther = web3.utils.fromWei(balanceInWei, 'ether');
        document.getElementById('contractBalance').innerText = 'Contract balance: ' + balanceInEther + ' ETH';
      } catch (error) {
        console.error('Failed to get contract balance:', error);
        alert('Failed to get contract balance. See console for details.');
      }
    }

    // Inisialisasi saat halaman dimuat
    window.onload = init;
  </script>
</body>
</html>

Pastikan untuk mengganti YOUR_CONTRACT_ADDRESS dengan alamat kontrak yang Anda dapatkan setelah melakukan migrasi. Anda juga perlu mengganti contractABI dengan ABI kontrak Anda.

2. Membuka File HTML di Browser

Buka file index.html di browser Anda. Pastikan Metamask Anda terhubung ke jaringan Ganache dan Anda memiliki akun dengan saldo ETH yang cukup. Anda akan melihat formulir sederhana yang memungkinkan Anda untuk memasukkan jumlah pembayaran dan membagi pembayaran.

Langkah 6: Pengujian dan Penyempurnaan

Setelah Anda memiliki DApp yang berfungsi, penting untuk mengujinya secara menyeluruh. Berikut adalah beberapa tips untuk pengujian:

  • Uji dengan berbagai jumlah pembayaran: Pastikan DApp berfungsi dengan benar dengan jumlah pembayaran yang berbeda, termasuk jumlah yang sangat kecil dan sangat besar.
  • Uji dengan jumlah penerima yang berbeda: Pastikan DApp berfungsi dengan benar dengan jumlah penerima yang berbeda.
  • Uji dengan akun yang berbeda: Pastikan DApp berfungsi dengan benar dengan akun yang berbeda.
  • Uji skenario kesalahan: Cobalah untuk melakukan pembayaran tanpa saldo yang cukup atau dengan alamat penerima yang tidak valid.

Setelah Anda menguji DApp Anda, Anda dapat menyempurnakannya lebih lanjut dengan menambahkan fitur tambahan, seperti:

  • Antarmuka pengguna yang lebih baik: Buat antarmuka pengguna yang lebih intuitif dan mudah digunakan.
  • Fitur keamanan tambahan: Tambahkan fitur keamanan tambahan untuk melindungi DApp Anda dari serangan.
  • Integrasi dengan layanan lain: Integrasikan DApp Anda dengan layanan lain, seperti bursa cryptocurrency atau penyedia pembayaran.

Kesimpulan

Selamat! Anda telah berhasil membuat DApp pembayaran terpisah sederhana. Panduan ini mencakup dasar-dasar pengembangan DApp, termasuk menyiapkan lingkungan pengembangan, menulis smart contract, menerapkan kontrak, dan berinteraksi dengan kontrak menggunakan Web3.js. Dengan pengetahuan ini, Anda dapat mulai menjelajahi dunia pengembangan DApp yang luas dan membangun aplikasi terdesentralisasi yang lebih kompleks.

Langkah Selanjutnya

Untuk melanjutkan perjalanan Anda di dunia pengembangan DApp, pertimbangkan untuk menjelajahi topik-topik berikut:

  • Framework pengembangan DApp lainnya: Selain Truffle, ada framework pengembangan DApp lainnya seperti Hardhat dan Brownie.
  • Bahasa pemrograman smart contract lainnya: Selain Solidity, ada bahasa pemrograman smart contract lainnya seperti Vyper.
  • Keamanan smart contract: Pelajari tentang potensi kerentanan dalam smart contract dan cara menghindarinya.
  • Pengembangan frontend yang lebih canggih: Pelajari tentang framework pengembangan frontend seperti React, Vue, dan Angular untuk membuat antarmuka pengguna yang lebih kompleks.

Semoga berhasil dalam perjalanan pengembangan DApp Anda!

“`

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *