Command Palette

Search for a command to run...

UnylyUnyly
Browse all

ChainLoyalty

FreeNot checked

πŸ”— Web3 loyalty API platform with blockchain rewards, NFT badges, and AI integration

GitHubEmbed

About

πŸ”— Web3 loyalty API platform with blockchain rewards, NFT badges, and AI integration

README

A plug-and-play Web3 loyalty API platform. Businesses send product events through a REST API, a configurable rules engine evaluates them, and the system issues rewards β€” points tracked in PostgreSQL, achievement badges minted as ERC-721 NFTs on Base Sepolia, or probabilistic lootbox-style payouts. Wallet identity replaces usernames. An MCP server exposes the entire loyalty engine as callable tools for AI clients like Claude Desktop and Cursor.

Built during a hackathon by the GitGoneWild team.


The Problem

Traditional loyalty programs are closed silos. Points live in proprietary databases, badges have no verifiable ownership, and integrating rewards into a new product means months of custom work. There is no standard API a SaaS product can call to say "this wallet just made a purchase" and have the rest handled automatically.

ChainLoyalty solves this by providing a single REST API that accepts product events, evaluates them against configurable rules (no code changes required), and distributes rewards. Wallet-based identity means users own their loyalty data. Achievement badges are real NFTs on Ethereum, verifiable by anyone. The entire system is accessible to AI agents through an MCP server, so a conversational interface can query analytics, inspect rules, and look up wallet activity without any custom integration.


What It Does

ChainLoyalty accepts events from any SaaS application through its REST API. When an event arrives β€” a purchase, a login, a signup, a referral β€” the rules engine evaluates it against every active rule for that client. Rules come in three types: threshold rules fire after N events of a given type, frequency rules fire on consecutive-day streaks, and conditional rules fire when event metadata satisfies a set of field-level conditions. When a rule matches, the rewards engine processes the configured payout.

Points are credited atomically via Prisma transactions β€” balance updates and transaction records are written together, so the ledger is always consistent. Badge rewards trigger an on-chain mint through the GGWBadge ERC-721 contract deployed on Base Sepolia. Probabilistic rewards roll against a configured probability before awarding the underlying points or badge. Every reward is logged once per rule per wallet to prevent duplicate payouts.

The referral system generates unique codes tied to referrer wallets, validates them against five fraud checks (self-referral, duplicate referral, code validity, bulk detection, circular chain detection), and credits both parties when the referee completes a qualifying event.

The frontend is a React application with MetaMask integration. It reads NFT badge ownership directly from the blockchain, displays GGW token balances from the ERC-20 contract, and communicates with the API for points, leaderboards, referrals, and event history.

The MCP server wraps all of this into 18 callable tools that any MCP-compatible AI client can invoke. An AI agent can query events, inspect rules, check wallet activity, pull leaderboards, and view platform-wide analytics β€” all through structured tool calls with validated inputs and typed responses.


MCP Server

The MCP server at packages/ChainLoyalty exposes the loyalty engine as tools for AI clients. It is built with mcp-use and connects to the same PostgreSQL database as the API server.

Running the MCP Server

cd packages/ChainLoyalty
cp .env.example .env
# Set DATABASE_URL to your PostgreSQL connection string
npm install
npm run dev

The server starts on http://localhost:3000 by default.

Registered Tool Modules

The server registers six tool modules at startup. Each module defines multiple tools with zod schema validation on inputs.

Events (src/tools/events.ts)

Tool Inputs What It Returns
query-events wallet, eventType, startDate, endDate, limit Filtered event list with metadata
get-event-types none Distinct event type strings across the platform
count-events wallet, eventType, groupBy Aggregate counts, optionally grouped by type or date

Rewards (src/tools/rewards.ts)

Tool Inputs What It Returns
get-rewards wallet Points balance, badge list, recent transactions
get-leaderboard limit Top users ranked by total points
get-badge-owners badgeTypeId Wallets owning a specific badge type

Rules (src/tools/rules.ts)

Tool Inputs What It Returns
list-rules active, type, eventType Filtered rule list
evaluate-rule ruleId, sampleEvent Step-by-step evaluation breakdown (event type match, active check, threshold/condition checks)
get-rule-details ruleId Full rule definition including conditions and reward config

Referrals (src/tools/referrals.ts)

Tool Inputs What It Returns
get-referral-stats wallet Code count, referral count, conversion rate
lookup-code code Code validity, referrer wallet, uses remaining
get-top-referrers limit Referrer leaderboard

Wallet (src/tools/wallet.ts)

Tool Inputs What It Returns
check-wallet wallet Existence check and summary
get-wallet-activity wallet, limit Recent events and transactions
wallet-summary wallet Comprehensive overview: points, badges, referrals, events

Analytics (src/tools/analytics.ts)

Tool Inputs What It Returns
platform-stats none Total users, events, points issued, active rules
active-users days Count of unique active wallets over a time window
engagement-trends days Daily event counts and trend data

Connecting from Claude Desktop

Add to your Claude Desktop MCP configuration:

{
  "mcpServers": {
    "chainloyalty": {
      "url": "http://localhost:3000"
    }
  }
}

Once connected, the AI client can call any registered tool by name with the documented inputs.


Architecture

ChainLoyalty is a monorepo with five packages, a frontend application, and a prototype server.

Client App                Frontend (React + Vite)
    |                           |
    | POST /api/v1/events       | MetaMask / ethers.js
    v                           v
+-------------------+    +-------------------+
|   API Server      |    | Base Sepolia Testnet |
|   (Express.js)    |    |  (ERC-721, ERC-20)|
|                   |    +-------------------+
|  Routes:          |           ^
|   /auth           |           | mint / query
|   /events --------+---> Rules Engine
|   /rewards        |       |
|   /referrals      |       v
|   /wallet         |    Reward Processor
|   /badges         |       |
|   /admin/rules    |       +---> Points (Prisma tx)
|                   |       +---> Badge (blockchain mint)
+--------+----------+       +---> Probabilistic (roll + award)
         |
         v
   PostgreSQL (Prisma ORM)
         ^
         |
+--------+----------+
|   MCP Server      |
|   (mcp-use)       |
|   18 tools        |
+-------------------+
         ^
         |
   AI Client (Claude Desktop, Cursor)

Request Flow

When a client submits an event:

  1. The request hits POST /api/v1/events with an API key header.
  2. apiKeyAuth middleware validates the key against bcrypt hashes stored in the clients table.
  3. eventValidator checks the payload with zod schemas. The eventId field enforces idempotency β€” duplicate submissions are rejected.
  4. eventService persists the event to PostgreSQL via Prisma.
  5. rulesEngine.evaluateRulesForEvent() fetches all active rules for this client whose eventTypes array includes the submitted event type.
  6. Each rule is dispatched to its type-specific evaluator:
    • Threshold: thresholdRule.ts counts prior events for this wallet and event type. If the count meets rule.threshold and no RewardLog exists for this wallet+rule pair, the reward is granted.
    • Frequency: frequencyRule.ts fetches recent events, deduplicates by calendar day, and calculates the current consecutive-day streak. If the streak meets rule.frequency, the reward is returned.
    • Conditional: conditionalRule.ts evaluates each condition in the rule's conditions array against the event's metadata using AND logic. Supported operators: eq, gt, gte, lt, lte, contains.
  7. For each matched rule, applyRewardWithLog checks RewardLog for deduplication, then dispatches by reward type:
    • POINTS: creditPoints() runs a Prisma transaction to update PointsBalance and create a PointsTransaction.
    • BADGE: awardBadge() calls the blockchain service, which sends a transaction to the GGWBadge contract's awardBadge() function.
    • PROBABILISTIC: A random roll is compared against the configured probability. If it wins, the underlying points or badge reward is awarded.
  8. A RewardLog entry is created to prevent the same rule from rewarding the same wallet twice.

Key Source Files

File Purpose
packages/api/src/server.ts Express app setup, middleware, route registration
packages/api/src/services/rules/rulesEngine.ts Orchestrates rule evaluation for an event
packages/api/src/services/rules/thresholdRule.ts Threshold rule evaluator
packages/api/src/services/rules/frequencyRule.ts Streak-based frequency evaluator
packages/api/src/services/conditionalRule.ts Condition evaluator with operator dispatch
packages/api/src/services/rewardProcessor.ts Reward processing with blockchain integration
packages/api/src/services/blockchain.ts Ethers.js contract interactions for badge minting
packages/api/src/services/fraudDetection.ts Five-check referral fraud prevention
packages/ChainLoyalty/index.ts MCP server entry point
packages/sdk/src/client.ts TypeScript SDK main client
packages/contracts/contracts/GGWBadge.sol ERC-721 badge NFT contract
packages/contracts/contracts/GGWToken.sol ERC-20 rewards token contract

Repository Structure

GitGoneWild/
  packages/
    api/                    # Express.js REST API server
      src/
        config/             # Database, contracts, app config
        middleware/          # apiKeyAuth, walletAuth, rate limiting
        routes/             # auth, events, rewards, referrals, wallet, badges
          admin/            # rules CRUD
        services/           # Business logic
          rules/            # rulesEngine, thresholdRule, frequencyRule, conditionalRule
        validators/         # Zod schemas for request validation
      prisma/
        schema.prisma       # Database schema (10 models)
    ChainLoyalty/           # MCP server
      src/
        tools/              # events, rewards, rules, referrals, wallet, analytics
        utils/              # prisma client, formatters, validators
      index.ts              # Server entry point
    contracts/              # Solidity smart contracts
      contracts/
        GGWBadge.sol        # ERC-721 achievement badges
        GGWToken.sol        # ERC-20 rewards token
      scripts/
        deploy.js           # Deployment script
      deployments-sepolia.json
    sdk/                    # TypeScript SDK (@gitgonewild/chainloyalty)
      src/
        modules/            # auth, events, rewards, referrals, admin
        utils/              # HTTP client, wallet utilities
        client.ts           # Main SDK class
        types.ts            # Full type definitions
  frontend/                 # React + Vite application
    src/
      components/           # UI components (Hero, Navbar, Footer, Analytics, demo)
        layout/             # AuthShell, sidebar
        ui/                 # Reusable UI primitives
      context/              # AuthContext (MetaMask state management)
      hooks/                # useApi, useDemoFlow, useReducedMotion
      lib/                  # web3.js, api.js, tokenService, paymentService
      pages/                # Dashboard, Rewards, Badges, Referrals, Leaderboard, etc.
  prototype/                # Single-file demo server (Express + Socket.IO)
    server.js               # In-memory rules engine, WebSocket real-time updates
    public/                 # Static HTML test pages
  docs/                     # Architecture research and findings

Getting Started

Prerequisites

  • Node.js 18+
  • PostgreSQL database (local or hosted, e.g. Supabase/Neon)
  • MetaMask browser extension (for frontend wallet features)

1. Clone and Install

git clone <repo-url>
cd GitGoneWild
npm install

The root package.json defines workspaces under packages/*, so npm install at the root installs dependencies for all packages.

2. Configure the API Server

cd packages/api
cp .env.example .env

Edit .env with your database connection string and other values:

DATABASE_URL="postgresql://user:password@host:5432/chainloyalty?sslmode=require"
PORT=8000
JWT_SECRET="generate-a-real-secret"

3. Set Up the Database

cd packages/api
npx prisma generate
npx prisma db push

This creates all tables defined in prisma/schema.prisma: clients, events, points_balances, points_transactions, rules, reward_logs, referral_codes, referrals, wallet_sessions, and badge_ownerships.

4. Start the API Server

cd packages/api
npm run dev

The server starts on port 8000 by default. Swagger documentation is available at http://localhost:8000/api-docs.

5. Start the Frontend

cd frontend
cp .env.example .env
npm install
npm run dev

The Vite dev server starts on port 5173. Connect MetaMask to Base Sepolia testnet (Chain ID: 84532) to interact with wallet features.

6. Start the MCP Server (optional)

cd packages/ChainLoyalty
cp .env.example .env
npm install
npm run dev

7. Run the Prototype (optional)

cd prototype
npm install
node server.js

The prototype runs on port 3000 with an in-memory data store and Socket.IO for real-time reward broadcasts. It serves static HTML test pages at /phase1, /phase2, /phase3, and /events.


API Reference

All API routes are prefixed with /api/v1. Routes marked with "API Key" require an x-api-key header. Routes marked with "JWT" require a Bearer token from the auth flow.

Authentication

Method Path Auth Description
POST /api/v1/auth/metamask None Validate wallet address, return session info
GET /api/v1/auth/challenge None Generate SIWE authentication challenge with nonce
POST /api/v1/auth/verify None Verify wallet signature, return JWT
GET /api/v1/auth/status JWT Check current authentication status

Events

Method Path Auth Description
POST /api/v1/events API Key Submit a new event (idempotent via eventId)
GET /api/v1/events API Key Query events with filters (wallet, type, date range, pagination)
GET /api/v1/events/:eventId API Key Retrieve a single event by ID
GET /api/v1/events/stats/:wallet API Key Event statistics for a wallet
GET /api/v1/events/types/:wallet API Key Distinct event types for a wallet

Example: Submit an event

curl -X POST http://localhost:8000/api/v1/events \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{
    "eventId": "evt-unique-id-123",
    "eventType": "purchase",
    "walletAddress": "0xYourWalletAddress",
    "metadata": { "amount": 99.99, "category": "premium" }
  }'

Rewards

Method Path Auth Description
GET /api/v1/rewards/leaderboard API Key Top users ranked by points
GET /api/v1/rewards/:wallet API Key All rewards for a wallet (points + badges)
GET /api/v1/rewards/:wallet/rank API Key Wallet's rank on the leaderboard
POST /api/v1/rewards/claim API Key Claim pending rewards

Admin Rules

Method Path Auth Description
GET /api/v1/admin/rules API Key List all rules (filter by active, type, eventType)
POST /api/v1/admin/rules API Key Create a new rule
PUT /api/v1/admin/rules/:id API Key Update an existing rule
DELETE /api/v1/admin/rules/:id API Key Delete a rule

Example: Create a threshold rule

curl -X POST http://localhost:8000/api/v1/admin/rules \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{
    "name": "10th Purchase Bonus",
    "type": "THRESHOLD",
    "eventTypes": ["purchase"],
    "threshold": 10,
    "reward": { "type": "POINTS", "amount": 500 },
    "active": true
  }'

Referrals

Method Path Auth Description
POST /api/v1/referrals/generate JWT Generate a referral code for the authenticated wallet
POST /api/v1/referrals/apply JWT Apply a referral code (runs fraud checks)
GET /api/v1/referrals/:wallet/stats API Key Referral statistics for a wallet
GET /api/v1/referrals/my-codes JWT List referral codes for the authenticated wallet
GET /api/v1/referrals/code/:code None Public details for a referral code
POST /api/v1/referrals/validate None Check if a code can be applied

Wallet

Method Path Auth Description
POST /api/v1/wallet/metamask-login None Demo MetaMask login
GET /api/v1/wallet/info None Wallet details and admin status
POST /api/v1/wallet/reward None Record a reward transaction (demo)
POST /api/v1/wallet/purchase None Record a purchase transaction (demo)
GET /api/v1/wallet/transactions None Transaction history
GET /api/v1/wallet/demo-config None Demo config (token address, conversion rates)

Badges

Method Path Auth Description
GET /api/v1/badges/:wallet None All NFT badges owned by a wallet
GET /api/v1/badges/types/all None All available badge types
GET /api/v1/badges/:wallet/points None Total badge points for a wallet
GET /api/v1/badges/contract/status None Blockchain contract status

Rules Engine

Rules are stored in PostgreSQL and evaluated at runtime when events arrive. No code changes are needed to add, modify, or remove rules β€” everything is configured through the admin API.

Rule Types

Threshold β€” Fires when a wallet's cumulative event count for the specified event types reaches the configured threshold. Implemented in thresholdRule.ts. The evaluator counts events via prisma.event.count(), checks the threshold, verifies no existing RewardLog, then grants the reward and logs it.

{
  "name": "Loyal Customer",
  "type": "THRESHOLD",
  "eventTypes": ["purchase"],
  "threshold": 10,
  "reward": { "type": "BADGE", "badgeTypeId": 2 }
}

Frequency β€” Fires when a wallet maintains a consecutive-day streak of the specified event types. Implemented in frequencyRule.ts. Events are fetched in descending order, deduplicated by calendar day using date-fns, and the streak is calculated by walking backwards from today. If the streak meets rule.frequency, the reward is returned.

{
  "name": "7-Day Login Streak",
  "type": "FREQUENCY",
  "eventTypes": ["login"],
  "frequency": 7,
  "reward": { "type": "POINTS", "amount": 1000 }
}

Conditional β€” Fires when all conditions in the rule's conditions array are satisfied by the event's metadata (AND logic). Implemented in conditionalRule.ts. Each condition specifies a field, an operator, and a value. The evaluator extracts the field from event metadata and applies the operator.

Supported operators: eq (strict equality), gt, gte, lt, lte (numeric comparison), contains (string includes or array membership).

{
  "name": "Premium Purchase Bonus",
  "type": "CONDITIONAL",
  "eventTypes": ["purchase"],
  "conditions": [
    { "field": "amount", "operator": "gt", "value": 100 },
    { "field": "category", "operator": "eq", "value": "premium" }
  ],
  "reward": { "type": "POINTS", "amount": 250 }
}

Deduplication

Every reward is logged in the reward_logs table with a unique constraint on (walletAddress, ruleId). This ensures each rule can only reward each wallet once, regardless of how many matching events arrive afterward.


Rewards Engine

The reward processor (rewardProcessor.ts) handles three reward types.

Points β€” Credits are applied inside a Prisma $transaction. The PointsBalance record is created or updated atomically with a corresponding PointsTransaction record. The transaction type is EARNED for standard rewards, BONUS for probabilistic wins, and REFERRAL for referral credits.

Badges β€” Badge rewards call blockchain.mintBadge(), which sends a transaction to the GGWBadge contract on Base Sepolia. The contract enforces one badge per type per wallet on-chain via walletOwnsBadgeType. The service waits for transaction confirmation and extracts the tokenId from the BadgeAwarded event log. Six default badge types are created at contract deployment:

ID Name Tier Points
0 Early Adopter Bronze 50
1 First Purchase Bronze 100
2 Loyal Customer Silver 250
3 Referral Master Silver 300
4 Power User Gold 500
5 VIP Member Platinum 1000

Probabilistic β€” A Math.random() roll is compared against the rule's configured probability (0 to 1). If the roll is less than or equal to the probability, the underlying reward (points or badge) is awarded. The roll result is logged in RewardLog.rewardData for auditability, and the RewardLog entry is created regardless of whether the roll won β€” this prevents re-evaluation.


Referral System

The referral system is implemented across referralService.ts, fraudDetection.ts, and the /api/v1/referrals routes.

Flow

  1. An authenticated user calls POST /referrals/generate to create a referral code. Codes are formatted as REF-XXXXXX with configurable maxUses and optional expiration.
  2. A new user calls POST /referrals/apply with the code and their wallet address.
  3. Before the referral is recorded, runComprehensiveFraudCheck() runs five checks in sequence:
    • Self-referral: Compares referrer and referee wallet addresses.
    • Duplicate referral: Checks if the referee wallet already has a referral record (unique constraint on refereeWallet).
    • Code validity: Verifies the code exists, is active, has not expired, and has not reached its max uses.
    • Bulk detection: Counts referrals from the referrer in the last 60 minutes. More than 10 triggers a flag.
    • Circular referral: Walks the referral chain up to 3 levels deep to detect A->B->C->A patterns.
  4. If all checks pass, a Referral record is created with status PENDING.
  5. When the referee completes a qualifying event, creditReferralRewards() runs inside a Prisma transaction: the referrer receives 100 points, the referee receives 50 points, and the referral status is updated to COMPLETED.

Rate Limiting

Referral applications are rate-limited per wallet using an in-memory store: 5 attempts per 15-minute window.


Smart Contracts

Two Solidity contracts are deployed on Base Sepolia testnet.

GGWBadge (ERC-721)

An ERC-721 NFT contract for achievement badges. Inherits from OpenZeppelin's ERC721, ERC721URIStorage, ERC721Enumerable, Ownable, and ReentrancyGuard. Compiled with Solidity 0.8.24.

  • Badge types are stored on-chain with name, description, image URI, tier (Bronze/Silver/Gold/Platinum), and points value.
  • awardBadge() mints a single badge to a wallet, enforcing one badge per type per wallet.
  • batchAwardBadges() mints up to 50 badges in one transaction, skipping invalid or duplicate entries.
  • getWalletBadges() returns all token IDs, badge type IDs, and award timestamps for a wallet.
  • Six default badge types are created in the constructor.

Deployed: 0x13F56b999DbE6861D2D0321Fdc19aB7aF9FF0F73

GGWToken (ERC-20)

An ERC-20 token for the rewards system. Inherits from OpenZeppelin's ERC20, ERC20Burnable, Ownable, and ReentrancyGuard.

  • 100 points = 1 GGW token. Minimum redemption: 100 points. Maximum per transaction: 1,000,000 points.
  • Total supply cap: 100,000,000 GGW. Initial mint of 10,000,000 GGW to the deployer.
  • redeemPoints() mints tokens to a wallet based on points, callable only by the reward processor or owner.
  • batchRedeemPoints() processes up to 100 redemptions in one transaction.
  • burnWithReason() allows holders to burn tokens with a logged reason.

Deployed: 0x9fAd48C015F23FC4c9F0480948D8A4A455Ff8CE7

Deploying Contracts

cd packages/contracts
cp .env.example .env
# Set BASE_SEPOLIA_RPC_URL and PRIVATE_KEY
npm install
npx hardhat compile
npx hardhat run scripts/deploy.js --network baseSepolia

The deploy script writes contract addresses to deployments-sepolia.json.


Frontend

The frontend is a React application built with Vite. It uses react-router-dom for routing, ethers.js for blockchain interactions, framer-motion and gsap for animations, and recharts for data visualization.

Pages

Route Component Description
/ LandingPage Marketing landing page
/connect ConnectWallet MetaMask connection flow
/dashboard Dashboard User overview (requires auth)
/rewards Rewards Points balance and transaction history
/badges BadgesPage NFT badge gallery (reads from blockchain)
/referrals Referrals Referral code management and stats
/leaderboard Leaderboard Top users by points
/analytics Analytics Platform analytics
/profile Profile User profile
/demo DemoPage Interactive demo (requires auth)
/live-demo LiveDemoPage Live demo with real API calls
/token-purchase TokenPurchaseDemo GGW token purchase simulation

Auth Flow

AuthContext manages wallet state. On mount, it checks for existing MetaMask connections. connectWallet() requests account access, switches to Base Sepolia if needed, and fetches the GGW token balance from the ERC-20 contract. The context provides wallet, walletFull, points, ggwBalance, isAdmin, and isConnecting to all child components.

The demo admin wallet (0xE3e321436711B0cb2A4B488068b3ff6b4596d2a8) is recognized for elevated privileges in the demo flow.

Blockchain Integration

frontend/src/lib/web3.js wraps all ethers.js interactions. It reads GGW token balances, transfers tokens, queries NFT badge ownership from the GGWBadge contract, fetches badge metadata (name, tier, points value), and provides Etherscan/OpenSea URLs for on-chain assets.


TypeScript SDK

The @gitgonewild/chainloyalty SDK (packages/sdk) provides a typed client for the ChainLoyalty API.

import { ChainLoyalty } from '@gitgonewild/chainloyalty';

const client = new ChainLoyalty({
  apiKey: 'your-api-key',
  baseUrl: 'http://localhost:8000',
});

// Track an event
await client.events.track({
  eventType: 'purchase',
  walletAddress: '0x...',
  metadata: { amount: 100 },
});

// Get rewards
const rewards = await client.rewards.get('0x...');

// Generate a referral code
const code = await client.referrals.generate({ maxUses: 10 });

The SDK is organized into modules: auth (SIWE challenge/verify), events (track and query), rewards (balance, leaderboard, claim), referrals (generate, apply, validate), and admin (rules CRUD, API key management). All modules use a shared HTTPClient with configurable retries, timeouts, and debug logging.

Full type definitions are exported from packages/sdk/src/types.ts, covering 50+ interfaces for all request/response shapes. Tests are colocated with modules (.test.ts files).


Environment Variables

API Server (packages/api/.env)

Variable Required Default Description
DATABASE_URL Yes β€” PostgreSQL connection string
PORT No 8000 Server port
NODE_ENV No development Environment
JWT_SECRET Yes β€” Secret for signing JWTs
JWT_EXPIRES_IN No 24h JWT expiration
CORS_ORIGIN No localhost:3000,5173,3001,4173 Allowed origins (comma-separated)
RATE_LIMIT_WINDOW_MS No 900000 Rate limit window (15 min)
RATE_LIMIT_MAX_REQUESTS No 100 Max requests per window
BCRYPT_ROUNDS No 10 API key hashing rounds
BASE_SEPOLIA_RPC_URL For blockchain β€” Base Sepolia RPC endpoint
REWARD_PROCESSOR_PRIVATE_KEY For blockchain β€” Wallet key for minting
GGW_TOKEN_CONTRACT For blockchain β€” Deployed GGWToken address
GGW_BADGE_CONTRACT For blockchain β€” Deployed GGWBadge address

MCP Server (packages/ChainLoyalty/.env)

Variable Required Default Description
DATABASE_URL Yes β€” PostgreSQL connection string (same DB as API)
PORT No 3000 MCP server port
MCP_URL No http://localhost:3000 MCP server URL

Contracts (packages/contracts/.env)

Variable Required Default Description
BASE_SEPOLIA_RPC_URL Yes β€” Base Sepolia RPC endpoint
PRIVATE_KEY Yes β€” Deployer wallet private key
ETHERSCAN_API_KEY No β€” For contract verification

Frontend (frontend/.env)

Variable Required Default Description
VITE_API_URL No http://localhost:8000 API server URL
VITE_API_KEY No β€” API key for authenticated requests

Deployment

API Server

The API server is a standard Express.js application. Deploy it anywhere that runs Node.js β€” Railway, Render, Fly.io, or a VPS. Set environment variables for DATABASE_URL, JWT_SECRET, and optionally the blockchain variables.

cd packages/api
npm run build
node dist/server.js

Frontend

The frontend builds to static files with Vite.

cd frontend
npm run build

The output in frontend/dist/ can be served by any static hosting provider β€” Vercel, Netlify, Cloudflare Pages.

Smart Contracts

Contracts are already deployed on Base Sepolia. To redeploy or deploy to another network:

cd packages/contracts
npx hardhat run scripts/deploy.js --network baseSepolia

Update the contract addresses in the API server's environment variables and in frontend/src/lib/web3.js.

MCP Server

Deploy the MCP server alongside the API server. It needs access to the same PostgreSQL database.

cd packages/ChainLoyalty
npm run build
npm start

Database Schema

The Prisma schema defines 10 models across 5 domains:

Client Management: Client β€” API key holders with bcrypt-hashed keys.

Event Tracking: Event β€” Timestamped events with wallet, type, and JSON metadata. Idempotent via unique eventId.

Points and Rewards: PointsBalance β€” Current balance per wallet. PointsTransaction β€” Ledger of all point changes (EARNED, SPENT, REFERRAL, BONUS, ADJUSTMENT). RewardLog β€” One entry per wallet per rule to prevent duplicate rewards. BadgeOwnership β€” Tracks badge awards with optional blockchain data.

Rules Engine: Rule β€” Configurable rules with type (THRESHOLD, FREQUENCY, CONDITIONAL), event type filters, conditions JSON, and reward JSON.

Referral System: ReferralCode β€” Generated codes with max uses and expiration. Referral β€” Links referrer to referee with status tracking (PENDING, COMPLETED, EXPIRED).

Authentication: WalletSession β€” SIWE nonces, signatures, and JWT tokens.


Team

GitGoneWild

AI-ML Developer
Nikhil Pise
🧠 AI-ML Developer
GitHub
Full Stack
Darshan Ved
⚑ Full Stack Developer
GitHub
Full Stack
Vraj Ved
πŸ”§ Full Stack Developer
GitHub
Full Stack
Jash Thakkar
πŸ’» Full Stack Developer
GitHub

License

MIT

from github.com/N1KH1LT0X1N/ChainLoyalty

Installing ChainLoyalty

This server has no published package β€” it is built from source. Open the repository and follow its README.

β–Έ github.com/N1KH1LT0X1N/ChainLoyalty

FAQ

Is ChainLoyalty MCP free?

Yes, ChainLoyalty MCP is free β€” one-click install via Unyly at no cost.

Does ChainLoyalty need an API key?

No, ChainLoyalty runs without API keys or environment variables.

Is ChainLoyalty hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install ChainLoyalty in Claude Desktop, Claude Code or Cursor?

Open ChainLoyalty on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install β€” the config is generated automatically, no JSON editing.

Related MCPs

Compare ChainLoyalty with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All ai MCPs