A fully on-chain reputation protocol built on ERC-5484 Soulbound Tokens.
Wallet behaviour tracked on-chain. Score evolves. Medal art upgrades automatically. No IPFS dependency.
🌐 Live Demo • 💻 Source Code • 🔗 ReputationToken • 🔗 Engine Proxy • 🔗 ReputationVault
On-chain identity is broken. Wallets are anonymous. There is no way to distinguish a DeFi power user from a fresh wallet. This protocol fixes that.
The ERC-5484 Reputation System assigns every wallet a Soulbound Token — non-transferable, non-mintable by the holder — that reflects their on-chain behaviour score. As the wallet performs positive actions (DAO votes, loan repayments, airdrop holding), their score rises and their medal art upgrades automatically with no re-mint required.
The scoring engine is UUPS upgradeable — logic can evolve as the protocol matures. The token contract is intentionally immutable — SBT ownership records are the ground truth of on-chain identity and must be permanent.
- 🌐 Frontend App
- 🏛️ Architecture
- ✅ Deployed Contracts
- 🎖️ Reputation Tiers & Medal System
- ⚙️ Scoring Actions
- 🧩 Smart Contract Breakdown
- 🧪 Testing Strategy
- 🚀 Local Setup
A production-grade Web3 frontend ships alongside the protocol, deployed live at rst-reputation-protocol.vercel.app.
| Layer | Technology |
|---|---|
| Framework | Next.js 14 (App Router) |
| Web3 | Wagmi v2 · Viem · RainbowKit |
| Styling | Inline CSS · CSS Animations · Canvas API |
| Deployment | Vercel |
| Network | Ethereum Sepolia Testnet |
- Live reputation dashboard — real-time score, tier, voting power, and loan access pulled directly from contracts
- Dynamic SBT medal display — on-chain SVG decoded and rendered from
tokenURI()with no IPFS - All vault actions wired —
castVote,submitProposal,mintNFT,takeLoan,repayLoan,claimAirdrop,settleAirdrop— all executable from the UI - Live cooldown bars — per-action countdown timers that update every second
- 30-day airdrop progress bar — visual hold tracker with early-settle warning
- Animated tier showcase — auto-cycles through all 5 tiers with cinematic morph transitions
- Scroll-reveal sections — intersection observer based section animations
- Particle canvas background — same as landing page, with comet trails
cd web3-app
npm install
npm run devRequires MetaMask or any RainbowKit-supported wallet connected to Sepolia Testnet.
The system is split into three layers with clear separation of concerns:
┌─────────────────────────────────────────────────────┐
│ USER / DAPP │
│ Wagmi v2 · Viem · RainbowKit (Frontend) │
└────────────────────┬────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────┐
│ REPUTATION VAULT │
│ castVote() · takeLoan() · claimAirdrop() · ... │
│ 12h / 24h cooldowns · CEI strict · nonReentrant │
└────────────────────┬────────────────────────────────┘
│ recordAction()
┌────────────────────▼────────────────────────────────┐
│ REPUTATION ENGINE (UUPS Proxy) │
│ Score calculation · Tier resolution · SBT issuer │
│ ReputationMath library · Storage gap pattern │
└──────────┬──────────────────────────────────────────┘
│ issue() / burn()
┌──────────▼──────────────────────────────────────────┐
│ REPUTATION TOKEN (Immutable) │
│ ERC-5484 Soulbound · On-chain SVG medals │
│ _update() transfer lock · ERC-165 registered │
└─────────────────────────────────────────────────────┘
| Decision | Rationale |
|---|---|
| Token is immutable | SBT ownership is ground truth — upgradeability would allow silent record tampering |
| Engine is UUPS upgradeable | Scoring logic must evolve; token state must not |
| On-chain SVG medals | Zero IPFS dependency — token lives as long as Ethereum |
| Dynamic metadata | tokenURI() reads live score from engine — medal upgrades on score change, no re-mint |
_mint not _safeMint |
SBTs have no receiver contract — onERC721Received is meaningless and adds reentrancy surface |
_update() override |
Exhaustively blocks all OZ transfer paths in one hook |
All contracts deployed and verified on Ethereum Sepolia Testnet.
| Contract | Address | Etherscan |
|---|---|---|
| ReputationToken | 0x9c77Ce31a110e360d62e4eF8B1F4cf8576F70F46 |
🔎 View |
| ReputationEngine (Impl) | 0xC81532619d5fB4728932A43A77Bfea04c3df5957 |
🔎 View |
| ReputationEngine (Proxy) | 0x4eFC1adc7Dd594C4bB04865B6dCc5101392FaBD8 |
🔎 View |
| ReputationVault | 0xd53320CDEF6f3DfA54436D2806e765d6d6bD98b6 |
🔎 View |
Interact with the proxy address only — never the implementation directly.
Every wallet's SBT displays a dynamic on-chain SVG medal that reflects their current tier. No IPFS. No centralized server. The medal art is generated entirely in Solidity and upgrades automatically as score increases.
| Tier | Score Range | Medal Design | Voting Power | Loan Limit |
|---|---|---|---|---|
| Unranked | 0 – 99 | Grey hexagon + ? |
0.5× | None |
| Bronze 🥉 | 100 – 299 | Copper circle + 6-point star | 1× | 20% of collateral |
| Silver 🥈 | 300 – 599 | Silver circle + 5-point star | 1.5× | 40% of collateral |
| Gold 🥇 | 600 – 849 | Gold circle + crown + gems | 2× | 60% of collateral |
| Platinum 💎 | 850 – 1000 | Platinum ring + diamond | 3× | 80% of collateral |
Actions are recorded through the ReputationVault. Each action maps to a signed score delta enforced by the ReputationMath library. Raw deltas are never exposed — only the Action enum is accessible to callers.
| Action | Function | Score Delta | Cooldown |
|---|---|---|---|
| DAO Vote | castVote() |
+10 | 12 hours |
| DAO Proposal | submitProposal() |
+25 | 24 hours |
| Loan Repaid | repayLoan() |
+30 | None (natural gate) |
| Loan Defaulted | markDefault() |
−50 | None (owner only) |
| Airdrop Held 30d | settleAirdrop() |
+15 | None (natural gate) |
| Airdrop Dumped | settleAirdrop() |
−20 | None (natural gate) |
| NFT Minted | mintNFT() |
+5 | 12 hours |
Score is always clamped to [0, 1000]. Underflow and overflow are impossible by design.
src/
├── ReputationToken.sol # ERC-5484 SBT — immutable, transfer-locked
├── ReputationEngine.sol # UUPS scoring engine — issues SBTs, tracks scores
├── ReputationVault.sol # Action simulator — user entry point
├── interfaces/
│ ├── IReputationToken.sol # Full error + event surface for callers
│ └── IReputationEngine.sol # CEI order + reentrancy requirements documented
└── libraries/
├── ReputationMath.sol # Pure math — Action enum, score clamping, tier resolution
└── ReputationSVG.sol # On-chain SVG medal generator — 5 tier designs
- Enum-gated deltas — arbitrary
int256deltas are never exposed. OnlyActionenum variants can mutate scores. - Overflow guards —
_applyDelta()has early-exit guards for extreme deltas, future-proofing against new high-magnitude actions. - Single guard pattern —
_assertValidScore()is called once per public entry point._resolveTierUnchecked()avoids a double-guard intierName(). - Zero state — pure library. Zero reentrancy surface.
| Invariant | Enforced By |
|---|---|
| One SBT per wallet | s_walletToToken[to] != 0 check in issue() |
| Engine address immutable post-deploy | setEngine() reverts with EngineAlreadySet on second call |
| Transfer always reverts | _update() override — catches all OZ paths |
| Score always in [0, 1000] | ReputationMath.applyAction() — clamped by design |
| All storage writes before external calls | Strict CEI in recordAction() and all Vault functions |
| No re-entrancy | nonReentrant on all state-changing engine + vault functions |
| SBT auto-issued on first action | token.issue() called last in CEI — after all storage writes |
The project uses a 4-layer testing approach with Foundry.
test/
├── unit/
│ ├── ReputationMathTest.t.sol # Score math, tier resolution, delta clamping
│ ├── ReputationTokenTest.t.sol # SBT issuance, transfer lock, burn, ERC-5484
│ ├── ReputationEngineTest.t.sol # recordAction CEI, auth, score updates
│ └── ReputationVaultTest.t.sol # All actions, cooldowns, loan/airdrop lifecycle
├── integration/
│ └── ReputationFlowTest.t.sol # Full lifecycle: Unranked → Bronze → Gold
└── fuzz/
└── FuzzReputation.t.sol # Score bounds, loan math, SBT uniqueness
- Score never exceeds 1000 — fuzz tested across 50+ random action sequences
- Score never underflows to negative — loan default on zero score → still zero
- Cooldown enforcement — exact timestamp boundary testing
- Diamond hands vs paper hands — airdrop held 30d vs immediate settle
- CEI verification — mock engine tracks call order in vault tests
- SBT uniqueness — fuzz tested across random wallet addresses
# Full suite
forge test -v
# Vault tests only
forge test --match-contract ReputationVaultTest -vvvv
# Fuzz tests
forge test --match-path test/fuzz/* -vvvv- Foundry (nightly)
- Node.js 18+ (for frontend)
- Git
git clone https://github.com/NexTechArchitect/ERC-5484.git
cd ERC-5484
forge install OpenZeppelin/openzeppelin-contracts --no-commit
forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit
forge install foundry-rs/forge-std --no-commitCreate a .env file:
PRIVATE_KEY=0x...
DEPLOYER_ADDRESS=0x...
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
ETHERSCAN_API_KEY=...forge build
forge test -v
# Deploy to Sepolia
source .env && forge script script/DeployReputation.s.sol:DeployReputation \
--rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvvcd web3-app
npm install
npm run dev
# → http://localhost:3000Connect any RainbowKit-supported wallet to Sepolia Testnet to interact.
This repository is for educational and portfolio purposes. The smart contracts implement production-grade patterns and have been thoroughly self-audited, but have not undergone a formal external security audit. Do not use with real funds without a professional security review.
Engineered with ❤️ by NexTech Architect
Smart Contract Developer · Solidity · Foundry · Web3 Engineering