Overview
Implement score-based access control to gate features, content, or functionality based on user ZKScore.Basic Score Gating
Simple Score Check
Copy
import { ZKScoreClient } from '@zkscore/sdk';
const client = new ZKScoreClient({
apiKey: process.env.ZKSCORE_API_KEY
});
async function checkAccess(userAddress, requiredScore) {
try {
const score = await client.getScore(userAddress);
return score.total >= requiredScore;
} catch (error) {
console.error('Error checking score:', error);
return false;
}
}
// Usage
const hasAccess = await checkAccess(userAddress, 500);
if (hasAccess) {
// Grant access to premium feature
showPremiumContent();
} else {
// Show upgrade prompt
showUpgradePrompt();
}
Category-Based Gating
Copy
async function checkCategoryAccess(userAddress, category, requiredScore) {
try {
const breakdown = await client.getScoreBreakdown(userAddress);
return breakdown[category] >= requiredScore;
} catch (error) {
console.error('Error checking category score:', error);
return false;
}
}
// Check DeFi access
const hasDeFiAccess = await checkCategoryAccess(userAddress, 'defi', 200);
if (hasDeFiAccess) {
showDeFiFeatures();
}
Advanced Gating
Multi-Criteria Gating
Copy
class ScoreGate {
constructor(client) {
this.client = client;
}
async checkAccess(userAddress, criteria) {
try {
const score = await client.getScore(userAddress);
const breakdown = await client.getScoreBreakdown(userAddress);
// Check total score
if (criteria.totalScore && score.total < criteria.totalScore) {
return { access: false, reason: 'Insufficient total score' };
}
// Check category scores
for (const [category, requiredScore] of Object.entries(criteria.categories || {})) {
if (breakdown[category] < requiredScore) {
return { access: false, reason: `Insufficient ${category} score` };
}
}
// Check achievements
if (criteria.achievements) {
const achievements = await client.getAchievements(userAddress);
const achievementIds = achievements.map(a => a.id);
for (const requiredAchievement of criteria.achievements) {
if (!achievementIds.includes(requiredAchievement)) {
return { access: false, reason: 'Missing required achievement' };
}
}
}
return { access: true };
} catch (error) {
return { access: false, reason: 'Error checking access' };
}
}
}
// Usage
const gate = new ScoreGate(client);
const result = await gate.checkAccess(userAddress, {
totalScore: 600,
categories: {
defi: 200,
nft: 100
},
achievements: ['defi-pioneer', 'nft-collector']
});
if (result.access) {
grantAccess();
} else {
showAccessDenied(result.reason);
}
React Component Example
Score Gate Component
Copy
import React, { useState, useEffect } from 'react';
import { ZKScoreClient } from '@zkscore/sdk';
const ScoreGate = ({
userAddress,
requiredScore,
children,
fallback,
category,
requiredCategoryScore
}) => {
const [hasAccess, setHasAccess] = useState(false);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
checkAccess();
}, [userAddress, requiredScore, category, requiredCategoryScore]);
const checkAccess = async () => {
try {
setLoading(true);
setError(null);
const client = new ZKScoreClient({
apiKey: process.env.REACT_APP_ZKSCORE_API_KEY
});
if (category && requiredCategoryScore) {
const breakdown = await client.getScoreBreakdown(userAddress);
setHasAccess(breakdown[category] >= requiredCategoryScore);
} else {
const score = await client.getScore(userAddress);
setHasAccess(score.total >= requiredScore);
}
} catch (err) {
setError(err.message);
setHasAccess(false);
} finally {
setLoading(false);
}
};
if (loading) {
return <div>Checking access...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
if (hasAccess) {
return children;
}
return fallback || <div>Access denied</div>;
};
// Usage
function PremiumFeature() {
return (
<ScoreGate
userAddress={userAddress}
requiredScore={500}
fallback={<div>You need a score of 500+ to access this feature</div>}
>
<div>Premium content here!</div>
</ScoreGate>
);
}
Vue Component Example
Score Gate Directive
Copy
// score-gate.js
import { ZKScoreClient } from '@zkscore/sdk';
const client = new ZKScoreClient({
apiKey: process.env.VUE_APP_ZKSCORE_API_KEY
});
export const scoreGate = {
async inserted(el, binding) {
const { userAddress, requiredScore, category, requiredCategoryScore } = binding.value;
try {
let hasAccess = false;
if (category && requiredCategoryScore) {
const breakdown = await client.getScoreBreakdown(userAddress);
hasAccess = breakdown[category] >= requiredCategoryScore;
} else {
const score = await client.getScore(userAddress);
hasAccess = score.total >= requiredScore;
}
if (!hasAccess) {
el.style.display = 'none';
}
} catch (error) {
console.error('Score gate error:', error);
el.style.display = 'none';
}
}
};
// Usage in Vue component
export default {
directives: { scoreGate },
template: `
<div v-score-gate="{ userAddress, requiredScore: 500 }">
Premium content
</div>
`
};
Server-Side Gating
Express.js Middleware
Copy
// middleware/scoreGate.js
import { ZKScoreClient } from '@zkscore/sdk';
const client = new ZKScoreClient({
apiKey: process.env.ZKSCORE_API_KEY
});
export const scoreGate = (requiredScore, category, requiredCategoryScore) => {
return async (req, res, next) => {
try {
const userAddress = req.user.address; // From auth middleware
if (category && requiredCategoryScore) {
const breakdown = await client.getScoreBreakdown(userAddress);
if (breakdown[category] < requiredCategoryScore) {
return res.status(403).json({
error: 'Insufficient score',
required: requiredCategoryScore,
current: breakdown[category]
});
}
} else {
const score = await client.getScore(userAddress);
if (score.total < requiredScore) {
return res.status(403).json({
error: 'Insufficient score',
required: requiredScore,
current: score.total
});
}
}
next();
} catch (error) {
res.status(500).json({ error: 'Score check failed' });
}
};
};
// Usage
app.get('/premium-content',
scoreGate(500),
(req, res) => {
res.json({ content: 'Premium content here' });
}
);
Best Practices
- Graceful Degradation: Always provide fallbacks for failed checks
- Caching: Cache score data to reduce API calls
- User Feedback: Clearly communicate access requirements
- Security: Never trust client-side score checks alone
- Performance: Use batch operations when checking multiple users