ChainLoyalty
БесплатноНе проверен🔗 Web3 loyalty API platform with blockchain rewards, NFT badges, and AI integration
Описание
🔗 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:
- The request hits
POST /api/v1/eventswith an API key header. apiKeyAuthmiddleware validates the key against bcrypt hashes stored in theclientstable.eventValidatorchecks the payload with zod schemas. TheeventIdfield enforces idempotency — duplicate submissions are rejected.eventServicepersists the event to PostgreSQL via Prisma.rulesEngine.evaluateRulesForEvent()fetches all active rules for this client whoseeventTypesarray includes the submitted event type.- Each rule is dispatched to its type-specific evaluator:
- Threshold:
thresholdRule.tscounts prior events for this wallet and event type. If the count meetsrule.thresholdand noRewardLogexists for this wallet+rule pair, the reward is granted. - Frequency:
frequencyRule.tsfetches recent events, deduplicates by calendar day, and calculates the current consecutive-day streak. If the streak meetsrule.frequency, the reward is returned. - Conditional:
conditionalRule.tsevaluates each condition in the rule'sconditionsarray against the event'smetadatausing AND logic. Supported operators:eq,gt,gte,lt,lte,contains.
- Threshold:
- For each matched rule,
applyRewardWithLogchecksRewardLogfor deduplication, then dispatches by reward type:- POINTS:
creditPoints()runs a Prisma transaction to updatePointsBalanceand create aPointsTransaction. - BADGE:
awardBadge()calls the blockchain service, which sends a transaction to theGGWBadgecontract'sawardBadge()function. - PROBABILISTIC: A random roll is compared against the configured probability. If it wins, the underlying points or badge reward is awarded.
- POINTS:
- A
RewardLogentry 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
- An authenticated user calls
POST /referrals/generateto create a referral code. Codes are formatted asREF-XXXXXXwith configurablemaxUsesand optional expiration. - A new user calls
POST /referrals/applywith the code and their wallet address. - 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.
- If all checks pass, a
Referralrecord is created with statusPENDING. - 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 toCOMPLETED.
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
|
Nikhil Pise 🧠 AI-ML Developer |
Darshan Ved ⚡ Full Stack Developer |
Vraj Ved 🔧 Full Stack Developer |
Jash Thakkar 💻 Full Stack Developer |
License
MIT
Установка ChainLoyalty
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/N1KH1LT0X1N/ChainLoyaltyFAQ
ChainLoyalty MCP бесплатный?
Да, ChainLoyalty MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для ChainLoyalty?
Нет, ChainLoyalty работает без API-ключей и переменных окружения.
ChainLoyalty — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить ChainLoyalty в Claude Desktop, Claude Code или Cursor?
Открой ChainLoyalty на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
автор: modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
автор: xuzexin-hzCompare ChainLoyalty with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории ai
