Skip to content

About

Decentralised chat with MetaMask sign-in and token rewards. Solidity, Hardhat, Next.js.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Node Connect logo

Node Connect

A chat app whose whole backend is one Ethereum smart contract.
Sign in with MetaMask, add friends and chat; every account, friendship and message is a transaction that earns both sides tokens.

Live demo · Try it · How it works · Run locally · The contract

CI Uptime Solidity 0.8.19 Hardhat 2 Next.js 16 ethers 6 Hoodi testnet Hosted on Vercel

Chat screen: friends list on the left, the chat with bob on the right, the account name and a 13 TOK balance in the header

Last updated: 2026-10-16 · Live on Vercel (free), contract on the Hoodi testnet · a full rework is planned (see roadmap)


Contents

About

Most chat apps keep your account and your messages on a company's servers. Node Connect keeps them in a smart contract instead: your wallet address is your account, a friendship is recorded on chain for both people, and each message is appended to the chat the two of you share. There is no server and no database; the website is static files that talk to the contract through MetaMask.

To make activity worth something, the contract pays tokens: 5 for creating an account, 1 to each side for a friendship and 1 to each side for every message. A leaderboard ranks everyone by tokens.

Try it live

Open https://node-connect-sigma.vercel.app in a browser with the MetaMask extension. Every action is a transaction on the Hoodi testnet, so the account needs a little Hoodi ETH, which is free from a faucet such as the Google Cloud faucet or the PoW faucet.

MetaMask currently warns that the site and its contract are high risk. The live contract was deployed from a wallet whose key leaked, and wallet security services flag everything that wallet created. Redeploying from a fresh wallet is the first step of the rework (see Known limitations). To try the app without that warning, use the local chain; it needs no testnet ETH either.

Things to try in the first two minutes:

  1. Connect Wallet and approve the network switch: the app adds Hoodi to MetaMask if it is missing.
  2. Create an account with a username: the header balance shows 5 TOK once the transaction is mined.
  3. Open Add Friends and add someone: both of you get 1 TOK, and they appear in your friends list.
  4. Open the chat with that friend and send a message (Enter sends): both balances go up by 1.
  5. Open the Leaderboard to see everyone ranked by tokens.
Add Friends page: cards for dave and erin, each with an Add Friend button

Registered users you can add, read from the contract (how friendships work)

Leaderboard: alice 13, bob 12, carol 8, dave 7, erin 5 tokens

Everyone ranked by tokens (the reward rules)

Screenshots: the production build of this commit on a local Hardhat chain seeded with demo accounts (alice, bob, carol, dave, erin), 1440x900, 2026-10-16. The live site shows the same screens for Hoodi accounts.

Features

  • Wallet sign-in: MetaMask connects the account; the app switches MetaMask to the configured network and adds it when missing.
  • On-chain accounts: one username per address, stored in the contract.
  • Friends: add any registered user; the friendship is written for both sides.
  • Chat: messages between friends are stored on chain in one shared chat per pair, oldest first, and the chat reloads when a sent message is mined.
  • Token rewards: the contract pays 5 tokens per account, 1 to both sides per friendship and 1 to both sides per message; the header shows your balance.
  • Leaderboard of every user ranked by tokens.
  • Local chain mode: the same app runs against a Hardhat node with test accounts, no testnet ETH needed.

Why it exists

It started as a final-year project to learn how a dApp is built end to end: a Solidity contract, its tests, a deploy to a public testnet and a frontend that talks to it through a wallet. Bringing it up to date in 2026 (Next.js 16, ethers 6, Hoodi after Holesky was retired, CI) taught the rest: a leaked deployer key does not stop mattering when the file is deleted, and putting everything on chain makes every click cost a wallet confirmation and every message public.

How it works

flowchart LR
    U["Browser + MetaMask"] --> V
    subgraph Vercel["Vercel (free)"]
        V["Static Next.js export<br/>no server code"]
    end
    U -- "reads (eth_call) and signed<br/>transactions, via ethers 6" --> R["Public Hoodi RPC node"]
    R --> C[("ChatApp contract<br/>Hoodi testnet")]
Loading

What happens when you send a message:

sequenceDiagram
    actor A as You
    participant UI as Chat (ChatAppContext)
    participant M as MetaMask
    participant C as ChatApp contract
    A->>UI: type a message, press Enter
    UI->>M: sendMessage(friend, text)
    M->>A: confirm the transaction and its gas
    M->>C: signed transaction
    C->>C: check you are friends, append to the shared chat, +1 token to both
    C-->>UI: transaction mined
    UI->>C: readMessage(friend), balances for the leaderboard
    UI-->>A: chat and balance refreshed
Loading

The page holds no state of its own beyond what it read last: after each mined transaction, Context/ChatAppContext.js reads the account, friends, chat and balances from the contract again.

The contract

contracts/ChatApp.sol is the whole backend.

Call Who can call it Effect Tokens
createAccount(name) an address without an account; the name must not be empty stores the username +5 to you
addFriend(address, name) a registered user, for another registered user who is not already a friend and not themselves adds the friendship to both lists +1 to both
sendMessage(friend, text) friends only appends to the chat keyed by the hash of both addresses +1 to both
readMessage(friend) anyone (eth_call) returns the chat, oldest first -
getAllAppUser(), getMyFriendList(), getUsername(address) anyone (eth_call) read accounts and friends -
mineMessageSafe(friend, nonce) anyone +1 when keccak(chat, last message, nonce) is below a fixed target; not used by the UI +1 to the caller

Tokens are a balance kept inside the contract (minerReward), not an ERC-20 token, so they do not show up in a wallet.

Tech stack

Layer Technology
Smart contract Solidity 0.8.19, Hardhat 2 (compile, local node, tests, deploy)
Frontend Next.js 16 (static export), React 18, CSS Modules
Chain access ethers 6 through MetaMask (BrowserProvider)
Network Ethereum Hoodi testnet (chain 560048); a local Hardhat node (chain 1337) for development
Tests and checks Hardhat tests (Mocha, Chai), ESLint (Next.js rules), an ABI freshness check
CI and hosting GitHub Actions (CI on every push, daily uptime check), Vercel Hobby
Local setup Node 22 pinned with mise

Design decisions

  1. The contract is the whole backend. No server to run or pay for, and no one can edit the history. Trade-off: every write needs a wallet confirmation and gas, and everything stored is public, messages included.
  2. A static export on Vercel. The site is files only, so it is free to host and fast (Lighthouse performance 99 on desktop). Trade-off: there is no server to index data, so the leaderboard makes one call per user and sorts in the browser.
  3. Reads go through the user's wallet. One provider for reads and writes keeps the code small. Trade-off: without MetaMask the app cannot show any data.
  4. Configuration is checked in one place at build time. Context/config.js stops the build when the contract address or network is missing or malformed, so a bad deploy never goes live.
  5. The contract ABI is a checked-in file, kept fresh by CI. The frontend imports Context/ChatApp.json, and CI fails when it differs from the compiled contract.
Project structure
contracts/ChatApp.sol      the smart contract (accounts, friends, messages, rewards)
test/ChatApp.test.js       contract tests (Hardhat)
scripts/deploy.js          deploys the contract; export-abi.js copies the ABI to Context/
Context/config.js          reads and checks every environment variable (the only place that does)
Context/networks.js        networks MetaMask can be switched to (hoodi, sepolia, localhost)
Context/ChatAppContext.js  app state, read again from the contract after each mined transaction
Utils/apiFeature.js        MetaMask connection and the contract instance
Components/                NavBar, Friend list and Chat, UserCard, Model (create account), Error
pages/                     / (chat), /alluser (add friends), /leaderboard
.github/workflows/         ci.yml (lint, tests, ABI check, build), uptime.yml (daily)

Engineering quality

Area What is in place
Tests 9 Hardhat tests of the contract: accounts (reward, empty name, duplicates), friends (both sides, self, duplicate, unregistered), messages (shared chat order, non-friends rejected) and mining; all passing on 2026-10-16
CI GitHub Actions on every push: ESLint, the contract tests, a check that Context/ChatApp.json matches the compiled contract, and the production build
Uptime A daily workflow requests /, /alluser and /leaderboard on the live site and fails unless each answers 200 with the app
Security No secrets in the frontend (only public NEXT_PUBLIC_ values); the deployer key lives only in a local .env; security headers from vercel.json (nosniff, DENY framing, referrer and permissions policies)
Measured Lighthouse on the live site, 2026-10-12 (mobile / desktop): performance 89-90 / 99, accessibility 100 / 100, best practices 100 / 100, SEO 100 / 100
Dependencies npm audit --omit=dev (what ships to the browser) reports no vulnerabilities; the remaining findings are in Hardhat's development toolchain

Run them:

npm run lint      # ESLint
npm test          # contract tests
npm run build     # static export to out/

Run it locally

Works on Windows (Git Bash), macOS and Linux. You need Git, Node 22 (pinned in mise.toml; mise installs it) and the MetaMask browser extension.

git clone https://github.com/A-RYAN-1/node-connect.git
cd node-connect
mise install            # skip if you manage Node another way
npm ci
cp .env.example .env    # the defaults point at the public Hoodi contract
npm run dev

Open http://localhost:3000, connect MetaMask and approve the switch to Hoodi. Writes need a little Hoodi ETH from a faucet (see Try it live).

On a local chain (no testnet ETH, no MetaMask warning):

npm run node            # terminal 1: Hardhat node on http://127.0.0.1:8545 with funded test accounts
npm run deploy-local    # terminal 2: deploys the contract and prints its address

In .env, set NEXT_PUBLIC_CONTRACT_ADDRESS to the printed address and NEXT_PUBLIC_NETWORK=localhost, run npm run dev, and import one of the test accounts npm run node prints into MetaMask. Those accounts and keys are public and only for the local chain.

Deploy your own contract to Hoodi
  1. Create a fresh MetaMask account that will only ever hold testnet ETH, and fund it from a Hoodi faucet.
  2. Put its private key in .env as DEPLOYER_PRIVATE_KEY (optionally an Alchemy or Infura URL as HOODI_RPC_URL).
  3. Run npm run deploy and set NEXT_PUBLIC_CONTRACT_ADDRESS to the address it prints.
  4. If you changed the contract, run npm run abi so the frontend uses the new ABI.
Troubleshooting
  • The build stops with a config error. Context/config.js checks the variables; copy .env.example to .env (or set them on the host) and build again.
  • MetaMask shows the wrong network. Click Connect Wallet again and approve the network switch.
  • A transaction fails with "insufficient funds". The account needs a little Hoodi ETH.
  • Local chain: MetaMask reports a nonce error after restarting npm run node. The chain was reset; in MetaMask, Settings, Advanced, clear the activity data for that account.
  • npm ci fails on Node 18 or 20. The project needs Node 22 (mise install).

Environment variables

All of them are listed with comments in .env.example.

Variable What it is Needed
NEXT_PUBLIC_CONTRACT_ADDRESS Address of the deployed ChatApp contract. Public. app (build time)
NEXT_PUBLIC_NETWORK Network MetaMask is switched to: hoodi, sepolia or localhost (Context/networks.js). Public. app (build time)
HOODI_RPC_URL Hoodi RPC URL; defaults to the free public node npm run deploy, optional
DEPLOYER_PRIVATE_KEY Key of a testnet-only deployer wallet. Secret: only in your local .env, never on the host npm run deploy

NEXT_PUBLIC_ values are compiled into the public JavaScript, so they must never hold a secret. Never commit a real .env file; only .env.example is tracked.

Deployment

The site is a static export on Vercel's free Hobby plan; the contract lives on the Hoodi testnet at 0x1C562FBbeA759113364Bf1EF282af19Bd8FD1A9f.

Part Where it runs How it deploys Variables it needs
Website Vercel Hobby (free), https://node-connect-sigma.vercel.app automatically on every push to main (Vercel Git integration; checked 2026-10-16) NEXT_PUBLIC_CONTRACT_ADDRESS, NEXT_PUBLIC_NETWORK (Production and Preview)
Contract Hoodi testnet by hand, npm run deploy from a local .env; never from CI DEPLOYER_PRIVATE_KEY, optional HOODI_RPC_URL (local only)

What a visitor notices (checked 2026-10-16): the site itself has no cold start; every write waits for a Hoodi block and needs test ETH from a faucet; the public RPC node is shared and can be slow at times.

Host your own copy on Vercel
  1. Import the repository in Vercel (framework: Next.js, no root directory).
  2. Set NEXT_PUBLIC_CONTRACT_ADDRESS and NEXT_PUBLIC_NETWORK in the project's Environment Variables for Production and Preview. Nothing secret is needed.
  3. Deploy. vercel.json adds the security headers; .vercelignore keeps env files and build output out of CLI uploads.

Status and roadmap

Reached: production baseline on 2026-10-12 (Next.js 16 and ethers 6, contract tests, lint and build in CI, checked configuration, security headers, a daily uptime check, the Lighthouse scores above), and auto-deploy on push since 2026-10-16. Checked by hand on the live site on 2026-10-13: adding a friend and sending a message on Hoodi.

Known limitations

  • MetaMask flags the site and the contract as high risk, because the contract was deployed from a wallet whose private key leaked (it was committed in 2025; the file is gone and the history was rewritten, but the key had already been taken). Only a redeploy from a fresh wallet fixes it.
  • Messages are stored as plain text on a public chain: anyone can read any chat.
  • Tokens are a balance inside the contract, not an ERC-20, and the rewards can be farmed with two accounts of your own. mineMessageSafe can be called again for the same message, so it is not safe to wire into the UI.
  • Adding a friend needs no consent from the other person, and there is no way to remove or block.
  • Every action costs a MetaMask confirmation and gas, then a wait for the block.
  • The leaderboard makes one call per user; lists such as getAllAppUser grow without a limit.
  • UI: the CHAT tab stays highlighted on every page, friend addresses are shown clipped without 0x, every friend gets the same avatar, and the GIFs in assets/ weigh about 14 MB.

Planned: the rework (agreed 2026-10-13; each step merged and deployed before the next)

  • Contracts and tests: an OpenZeppelin ERC-20 token (TOK) with a hard cap, a registry with friend requests (request, accept, decline, remove, block), deployed and verified from a fresh wallet, which should also end the MetaMask warning
  • Backend on Vercel Functions and Neon: Sign-In with Ethereum, a messages API that stores only ciphertext, and a scheduled job that anchors each day's message hashes on chain
  • End-to-end encrypted chats (keys derived from one wallet signature) and a new chat UI with pending and failed states
  • Real token mining: proof of activity plus proof of work, one claim per user per day, bound to the sender, with retargeting and halving; mined in a Web Worker
  • Production checks again (Slither in CI, API tests, Lighthouse), then this README

Credits

Built by Aryan Deshmukh (A-RYAN-1): the contract, its tests, the frontend, and the 2026 upgrade (Hoodi, Next.js 16, ethers 6, CI, deployment). RealFalseGod contributed the leaderboard page and the token balance in the header (October 2025).

About

Decentralised chat with MetaMask sign-in and token rewards. Solidity, Hardhat, Next.js.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages