Zum Inhalt springen

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

Send ETH to multiple people in one transaction, with a frontend to manage it!

✅ What We’re Building

We’ll create a Split Payment DApp that:

  • Lets users input multiple Ethereum addresses and amounts
  • Splits the ETH accordingly and sends it
  • Shows a history of all payments made through the contract

🧱 Step 1: Set Up the Smart Contract

1. Install Dependencies
Install Hardhat, a dev tool for Ethereum.

npm init -y
npm install --save-dev hardhat
npx hardhat

Choose „Create a basic sample project“ and follow the prompts.

Then, install these:

npm install --save-dev @nomicfoundation/hardhat-toolbox

2. Create the Smart Contract
Create contracts/SplitPayment.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract SplitPayment {
    // Owner of the contract
    address public owner;

    // Struct to record each payment details
    struct Payment {
        address sender;              // Address of the sender
        address[] recipients;       // List of recipient addresses
        uint256[] amounts;          // List of amounts sent to each recipient
        uint256 timestamp;          // Timestamp of when the payment was made
    }

    // Array to store all payment history
    Payment[] public payments;

    // Event emitted when a payment is successfully sent
    event PaymentSent(address indexed sender, address[] recipients, uint256[] amounts, uint256 timestamp);

    // Constructor sets the contract deployer as the owner
    constructor() {
        owner = msg.sender;
    }

    /**
     * @dev Splits the sent ETH among recipients based on specified amounts
     * @param recipients Array of recipient addresses
     * @param amounts Array of ETH amounts to be sent to each recipient
     */
    function splitPayment(address[] calldata recipients, uint256[] calldata amounts) external payable {
        // Ensure the lengths of recipients and amounts match
        require(recipients.length == amounts.length, "Recipients and amounts length mismatch");

        uint256 totalAmount;
        // Calculate total amount to be distributed
        for (uint256 i = 0; i < amounts.length; i++) {
            totalAmount += amounts[i];
        }

        // Ensure the sent ETH matches the total distribution amount
        require(msg.value == totalAmount, "Incorrect ETH sent");

        // Transfer respective amounts to each recipient
        for (uint256 i = 0; i < recipients.length; i++) {
            payable(recipients[i]).transfer(amounts[i]);
        }

        // Record the payment in history
        payments.push(Payment({
            sender: msg.sender,
            recipients: recipients,
            amounts: amounts,
            timestamp: block.timestamp
        }));

        // Emit the PaymentSent event
        emit PaymentSent(msg.sender, recipients, amounts, block.timestamp);
    }

    /**
     * @dev Returns the total number of payments made
     */
    function getPaymentsCount() external view returns (uint256) {
        return payments.length;
    }

    /**
     * @dev Retrieves the details of a specific payment by index
     * @param index The index of the payment to retrieve
     * @return sender The address who sent the payment
     * @return recipients The list of recipients
     * @return amounts The list of amounts sent to each recipient
     * @return timestamp The timestamp when the payment was made
     */
    function getPayment(uint256 index) external view returns (address sender, address[] memory recipients, uint256[] memory amounts, uint256 timestamp) {
        require(index < payments.length, "Invalid index");
        Payment storage payment = payments[index];
        return (payment.sender, payment.recipients, payment.amounts, payment.timestamp);
    }
}

🧪 Step 2: Compile & Deploy Smart Contract

1. Compile

npx hardhat compile

2. Deploy to Testnet (e.g. Sepolia)

  • Get test ETH from faucet
  • Configure hardhat.config.js:
require("@nomicfoundation/hardhat-toolbox");

module.exports = {
  networks: {
    sepolia: {
      url: "https://sepolia.infura.io/v3/",
      accounts: ["YOUR_PRIVATE_KEY"]
    }
  },
  solidity: "0.8.19",
};

  • Create scripts/deploy.js:
async function main() {
  const SplitPayment = await ethers.getContractFactory("SplitPayment");
  const contract = await SplitPayment.deploy();
  await contract.waitForDeployment();
  console.log("Contract deployed to:", contract.target);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Run deployment:

npx hardhat run scripts/deploy.js --network sepolia

🎨 Step 3: Build the Frontend (React)

1. Set up a React App

npx create-react-app split-dapp --template typescript
cd split-dapp
npm install ethers

2. Add Your Contract ABI
Save your ABI from Hardhat (artifacts/contracts/SplitPayment.sol/SplitPayment.json) into a file called SplitPaymentABI.ts:

export const SplitPaymentABI = [
  // paste the ABI here
];

3. Add the Frontend Code
Paste your frontend code into App.tsx. (You already shared this in your message.)

Replace the contract address with the deployed one:

const CONTRACT_ADDRESS = "0x..."; // your deployed address

🌐 Step 4: Connect to MetaMask
When you run the app (npm start), the browser will prompt you to connect MetaMask. Once connected:

  • Enter recipient addresses and ETH values
  • Click Send Payment
  • Use Load Payment History to see past transactions

🔐 Security Notes

  • Always test on testnets before mainnet
  • Add checks for duplicate addresses or suspicious inputs
  • Consider using OpenZeppelin libraries for added safety

✅ Summary

You now have:

  • A Solidity smart contract to split ETH
  • A React frontend to interact with the contract
  • Payment history tracking
  • MetaMask integration for ease of use

🧠 What to Learn Next?

  • Use Hardhat test scripts for automated testing
  • Upgrade to ERC20 token splits
  • Add login with WalletConnect or RainbowKit
  • Secure backend for storing analytics or events

Link to the github repo

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert