<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pratik Pangeni</title>
    <description>The latest articles on DEV Community by Pratik Pangeni (@pratik_pangeni_cf04835748).</description>
    <link>https://dev.to/pratik_pangeni_cf04835748</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4077315%2F10c3c129-8629-4ad0-9035-d643d1da4589.png</url>
      <title>DEV Community: Pratik Pangeni</title>
      <link>https://dev.to/pratik_pangeni_cf04835748</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pratik_pangeni_cf04835748"/>
    <language>en</language>
    <item>
      <title>Splitting the Bill, On-Chain: Building ExpenseShare, a Decentralized Expense Tracker</title>
      <dc:creator>Pratik Pangeni</dc:creator>
      <pubDate>Fri, 14 Aug 2026 08:07:24 +0000</pubDate>
      <link>https://dev.to/pratik_pangeni_cf04835748/splitting-the-bill-on-chain-building-expenseshare-a-decentralized-expense-tracker-3330</link>
      <guid>https://dev.to/pratik_pangeni_cf04835748/splitting-the-bill-on-chain-building-expenseshare-a-decentralized-expense-tracker-3330</guid>
      <description>&lt;h1&gt;
  
  
  Splitting the Bill, On-Chain: Building ExpenseShare, a Decentralized Expense Tracker
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;How I built a trustless, blockchain-powered expense-sharing app — from Solidity smart contracts to a live React frontend.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Every group trip, dinner, or shared apartment comes with the same awkward ritual: someone pays, someone tracks, and someone always &lt;em&gt;forgets to pay back&lt;/em&gt;. The spreadsheet becomes a mess, text-message IOUs get lost, and "who owes whom" is always a guessing game.&lt;/p&gt;

&lt;p&gt;What if the tracking, the splitting, and the settlement all happened automatically — with a permanent, tamper-proof record that nobody can dispute?&lt;/p&gt;

&lt;p&gt;That's exactly what &lt;strong&gt;ExpenseShare&lt;/strong&gt; does. It's a decentralized application (DApp) built on the Ethereum Sepolia testnet where expenses are split, tracked, and settled transparently on the blockchain.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;ExpenseShare lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connect your MetaMask wallet&lt;/strong&gt; and start splitting expenses instantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create expenses&lt;/strong&gt; with multiple participants — the smart contract calculates everyone's share automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track who owes whom&lt;/strong&gt; in real-time with live dashboard stats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send payment requests&lt;/strong&gt; and settle debts directly on-chain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flag bad debtors&lt;/strong&gt; when people don't pay up&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mint NFT receipts&lt;/strong&gt; as permanent proof that an expense was settled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing runs with &lt;strong&gt;zero backend&lt;/strong&gt;. There's no server, no central database — just a smart contract doing all the heavy lifting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React 19, Vite 8, Tailwind CSS 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web3&lt;/td&gt;
&lt;td&gt;ethers.js v5, MetaMask&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smart Contracts&lt;/td&gt;
&lt;td&gt;Solidity 0.8, Foundry (Forge)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFT Standard&lt;/td&gt;
&lt;td&gt;OpenZeppelin ERC721&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;IPFS via Pinata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;Ethereum Sepolia testnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;GitHub Actions, Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Smart Contracts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;Storage.sol&lt;/code&gt; — The Expense Manager
&lt;/h3&gt;

&lt;p&gt;This contract is the heart of the app. Every expense lives on-chain as an immutable record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum Status { pending, paid, rejected, badDebt }

struct Expense {
    string expname;
    string paidby;
    address payerAddress;
    string paddress;
    uint256 amt;
    uint256 shareamount;
    Status status;
    address[] participants;
    string[] participantNames;
    mapping(address =&amp;gt; bool) hasPaid;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key mechanics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Equal splitting&lt;/strong&gt; — the share is computed on-chain: &lt;code&gt;amt / (participants + 1)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle tracking&lt;/strong&gt; — every expense moves through &lt;code&gt;pending → paid&lt;/code&gt;, or falls into &lt;code&gt;rejected&lt;/code&gt; / &lt;code&gt;badDebt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payment requests&lt;/strong&gt; — a participant who wants their money back can create an on-chain request, and the debtor can settle it by sending ETH directly through the contract.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bad debt detection&lt;/strong&gt; — &lt;code&gt;getBadDebtors()&lt;/code&gt; scans participants who haven't paid, so defaulters are always identifiable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events everywhere&lt;/strong&gt; — &lt;code&gt;ExpenseAdded&lt;/code&gt;, &lt;code&gt;ParticipantPaid&lt;/code&gt;, &lt;code&gt;PaymentRequested&lt;/code&gt;, &lt;code&gt;PaymentCompleted&lt;/code&gt;, and &lt;code&gt;StatusUpdated&lt;/code&gt; let the frontend react to state changes in real time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;ExpenseNFT.sol&lt;/code&gt; — Proof of Settlement
&lt;/h3&gt;

&lt;p&gt;Each fully-paid expense can be minted into an &lt;strong&gt;NFT receipt&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract ExpenseNFT is ERC721, ERC721URIStorage, ERC721Pausable, Ownable, ERC721Burnable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Only the &lt;strong&gt;payer&lt;/strong&gt; (the actual owner) can mint, and only after the expense is fully &lt;strong&gt;paid&lt;/strong&gt; — it's a genuine receipt, not a participation trophy.&lt;/li&gt;
&lt;li&gt;NFT metadata and images are uploaded to &lt;strong&gt;IPFS via Pinata&lt;/strong&gt;, so the receipt lives permanently on decentralized storage.&lt;/li&gt;
&lt;li&gt;The NFT contract tracks which expense maps to which token, and users can even &lt;strong&gt;import their receipts straight into MetaMask&lt;/strong&gt; via &lt;code&gt;wallet_watchAsset&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Frontend
&lt;/h2&gt;

&lt;p&gt;The React app is deliberately simple in structure but rich in features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Landing page&lt;/strong&gt; with a full marketing story, feature grid, and "how it works" section&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth pages&lt;/strong&gt; (register/login) gated by a route guard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard&lt;/strong&gt; showing summary stats — pending, paid, received, and &lt;em&gt;payment due&lt;/em&gt; (what &lt;em&gt;you&lt;/em&gt; owe others)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic participant forms&lt;/strong&gt; — add up to 10 people with names and wallet addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live refresh&lt;/strong&gt; — the dashboard polls the chain every 15 seconds, so statuses update as participants pay&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bad debt section&lt;/strong&gt; that surfaces defaulters with their addresses and amounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark mode&lt;/strong&gt; toggled and persisted via &lt;code&gt;localStorage&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One nice touch: payments are processed in two steps. The participant sends ETH directly to the payer via &lt;code&gt;signer.sendTransaction&lt;/code&gt;, then the payer marks them as paid in the contract. This keeps real value flowing between wallets while the contract maintains the trusted record.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing &amp;amp; CI
&lt;/h2&gt;

&lt;p&gt;The project ships with &lt;strong&gt;7 Foundry tests&lt;/strong&gt; covering the full business logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding a single-expense and verifying stored details&lt;/li&gt;
&lt;li&gt;Multi-participant splitting&lt;/li&gt;
&lt;li&gt;Marking participants as paid and confirming the remaining bad debtor&lt;/li&gt;
&lt;li&gt;Creating and verifying payment requests&lt;/li&gt;
&lt;li&gt;Updating expense status&lt;/li&gt;
&lt;li&gt;Extracting all bad debtors from a 4-person expense&lt;/li&gt;
&lt;li&gt;A complete end-to-end flow: add → pay → all settled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub Actions runs &lt;code&gt;forge fmt --check&lt;/code&gt;, &lt;code&gt;forge build --sizes&lt;/code&gt;, and &lt;code&gt;forge test -vvv&lt;/code&gt; on every push, so the contract logic is continuously verified.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; live on Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart contracts:&lt;/strong&gt; deployed on the Sepolia testnet&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Deployed contract addresses are available in the repo's &lt;code&gt;src/Expenseapp.jsx&lt;/code&gt; and broadcast logs.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Challenges &amp;amp; Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wallet ↔ contract coordination.&lt;/strong&gt; Making real ETH transfers while keeping the on-chain ledger accurate required a careful two-step design — direct wallet-to-wallet payment, then an on-chain status update. It's the difference between a "ledger app" and a real settlement tool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gas-conscious events.&lt;/strong&gt; Converting view functions into event-emitting functions (e.g., &lt;code&gt;getStatus&lt;/code&gt;) taught me that on-chain state changes cost gas, and events are the cheap, standard way to surface state to the UI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NFT gating logic.&lt;/strong&gt; Deciding &lt;em&gt;who&lt;/em&gt; can mint a receipt NFT and &lt;em&gt;when&lt;/em&gt; (only the payer, only after full payment) forced me to think hard about what an NFT receipt should actually represent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sepolia chain management.&lt;/strong&gt; The app auto-switches users to Sepolia via &lt;code&gt;wallet_switchEthereumChain&lt;/code&gt; and gracefully handles the case where the network isn't added yet.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🔔 Notification system for due payments&lt;/li&gt;
&lt;li&gt;💳 ERC20 token support instead of raw ETH&lt;/li&gt;
&lt;li&gt;📊 Analytics dashboard with spending insights&lt;/li&gt;
&lt;li&gt;🔄 Automatic escrow settlement&lt;/li&gt;
&lt;li&gt;📱 Mobile app version&lt;/li&gt;
&lt;li&gt;🤖 AI-based expense prediction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix SPA routing on Vercel&lt;/strong&gt; (currently direct URL navigation to &lt;code&gt;/login&lt;/code&gt; or &lt;code&gt;/register&lt;/code&gt; returns 404 — a simple rewrite config fixes this)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install MetaMask and connect to the &lt;strong&gt;Sepolia&lt;/strong&gt; testnet (the app does this for you).&lt;/li&gt;
&lt;li&gt;Grab some free test ETH from a Sepolia faucet.&lt;/li&gt;
&lt;li&gt;Open the live app, create an expense, split it with friends, and mint your first receipt NFT.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building ExpenseShare showed me how blockchain genuinely solves a real-world coordination problem. There's no middleman, no spreadsheet, no "I'll pay you back later" — just transparent, immutable, trustless expense tracking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparency. Trustless execution. Accountability. Immutable records.&lt;/strong&gt; That's what happens when you put a bill on the blockchain.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Repo: &lt;a href="https://github.com/Pratikeeyyyy/metaapk" rel="noopener noreferrer"&gt;github.com/Pratikeeyyyy/metaapk&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>solidity</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>ethereum</category>
    </item>
  </channel>
</rss>
