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