A decentralized application that allows users to create and join communities (similar to Discord servers), interact via token-gated channels, and send messages securely through smart contracts and IPFS. Built with Solidity, Next.js, Ethers.js, and thoroughly tested using Playwright and Hardhat.
-
Smart Contract Powered Communities
Create, manage, and join communities on-chain. Ownership and access are enforced by smart contracts. -
Token-Gated Channels
Restrict access to communities or channels based on NFT or ERC-20 token ownership. -
Decentralized Messaging
Store messages on IPFS or emit them as smart contract events for full decentralization. -
Wallet Authentication
Users log in with MetaMask or WalletConnect. -
Real-Time Updates
Integrates with The Graph or contract polling to reflect real-time community activity.
| Layer | Stack / Tools |
|---|---|
| Smart Contracts | Solidity, Hardhat, OpenZeppelin |
| Frontend | Next.js, React, TailwindCSS |
| Web3 | ethers.js, wagmi, viem, RainbowKit |
| Storage | IPFS (via web3.storage or Pinata) |
| Indexing | The Graph (optional) |
| CI / Testing | Playwright, Hardhat, Slither, Foundry (optional) |
| Blockchain | Ethereum (Sepolia), Zircuit L2 (optional) |
-
CommunityManager.sol:
Manages creation and metadata for communities. -
AccessControl.sol:
Assigns roles (Owner, Mod, Member) and restricts access to actions. -
TokenGating.sol:
Validates token/NFT ownership before allowing access to protected channels.
- Connect wallet using RainbowKit / wagmi
- Create/join a community
- View list of communities and members
- Send messages (stored via IPFS)
- Admin controls for community owners
- Written in Hardhat using Mocha/Chai
- Covers:
- Community creation
- Access control
- Reverts and edge cases
- Written in Playwright
- Covers:
- Wallet connection
- UI + smart contract interaction
- Creating/joining communities
- Sending & retrieving messages
test("Create community flow", async ({ page }) => {
await page.goto("/");
await page.click('button:has-text("Connect Wallet")');
await page.fill('[placeholder="Community Name"]', "Web3 Ninjas");
await page.click("text=Create");
await expect(page.getByText("Community created")).toBeVisible();
});