Разработка системы верификации игроков крипто-казино
Крипто-казино работают в условиях двойного давления: с одной стороны — пользователи, которые ценят анонимность и пришли в Web3 именно за ней; с другой — регуляторы и платёжные партнёры, которые требуют KYC, AML-скрининг и проверку возраста. Найти баланс между этими требованиями — архитектурная задача, не только юридическая.
Уровни верификации
Не все пользователи требуют одинаковой верификации. Tiered approach — стандарт для gambling платформ:
Tier 0 — минимальный (до $500/месяц): электронная почта, wallet подключение, auto AML скрининг адреса (Chainalysis или Elliptic). Никаких документов, ответ моментальный.
Tier 1 — базовый (до $5,000/месяц): имя + дата рождения + страна проживания. Автоматическая проверка через sanctions lists. Подтверждение аккаунта по email или SMS.
Tier 2 — расширенный (до $50,000/месяц): Government ID (паспорт, Driver's License), liveness check (selfi с документом), адрес проживания (utility bill). Verifier: Sumsub, Onfido, или аналог.
Tier 3 — enhanced due diligence (> $50,000/месяц или VIP): Source of Funds (откуда деньги), Source of Wealth, расширенный PEP/Sanctions check, ручная проверка compliance офицером.
Техническая интеграция KYC
Sumsub — стандартный выбор для gambling
Sumsub предоставляет SDK для web и mobile, WebSDK для встроенного flow:
// Генерация SDK token на бэкенде
async function getSumsubToken(applicantId: string): Promise<string> {
const timestamp = Math.floor(Date.now() / 1000);
const method = 'POST';
const url = `/resources/accessTokens?userId=${applicantId}&levelName=basic-kyc-level`;
const signature = crypto
.createHmac('sha256', SUMSUB_SECRET_KEY)
.update(timestamp + method + url)
.digest('hex');
const response = await axios.post(
`https://api.sumsub.com${url}`,
{},
{
headers: {
'X-App-Token': SUMSUB_APP_TOKEN,
'X-App-Access-Sig': signature,
'X-App-Access-Ts': timestamp,
}
}
);
return response.data.token;
}
// Frontend инициализация SDK
import SumsubWebSdk from "@sumsub/websdk";
const sdk = SumsubWebSdk.init(
accessToken,
() => refreshToken(), // callback для обновления токена
{
lang: "ru",
onMessage: (type, payload) => {
if (type === "idCheck.onApplicantStatusChanged") {
if (payload.reviewResult?.reviewAnswer === "GREEN") {
handleKYCApproved(payload.applicantId);
}
}
},
onError: (error) => console.error("Sumsub error:", error),
}
);
sdk.launch("#sumsub-container");
Webhook обработка результатов
Sumsub присылает webhook при изменении статуса. Важный момент — проверка подписи webhook, чтобы не принять поддельный callback:
function verifySumsubWebhook(req: Request): boolean {
const signature = req.headers['x-payload-digest'];
const secret = process.env.SUMSUB_WEBHOOK_SECRET;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(req.rawBody) // raw body, не parsed JSON
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
async function handleSumsubWebhook(payload: SumsubWebhookPayload) {
const { applicantId, reviewResult, type } = payload;
if (type === "applicantReviewed") {
if (reviewResult.reviewAnswer === "GREEN") {
await db.updateUserKYCStatus(applicantId, "APPROVED", reviewResult.reviewRejectType);
await updateUserTier(applicantId);
} else if (reviewResult.reviewAnswer === "RED") {
await db.updateUserKYCStatus(applicantId, "REJECTED", reviewResult.moderationComment);
await notifyUser(applicantId, "kyc_rejected");
}
}
}
AML скрининг криптотранзакций
Для казино особенно критично: деньги из darknet markets, stolen funds — прямая ответственность платформы.
Интеграция Chainalysis KYT (Know Your Transaction)
async function screenAddress(address: string, asset: string): Promise<RiskScore> {
const response = await chainalysisClient.post('/v1/users', {
userId: address,
});
const transferResponse = await chainalysisClient.post('/v1/transfers', {
network: asset,
asset: asset,
transferReference: address,
direction: 'received',
});
return {
riskScore: transferResponse.data.riskScore,
cluster: transferResponse.data.cluster?.name,
category: transferResponse.data.cluster?.category,
};
}
Risk categories для автоматического блокирования: darknet market, stolen funds, ransomware, sanctions. Для таких адресов — автоматический reject депозита и заморозка аккаунта без ручного review.
Grey zone категории (gambling, P2P exchange, mixing): требуют ручной review compliance офицера, не автоматического блока.
OFAC Sanctions Screening
Отдельно от криптоскрининга — проверка wallet адресов в OFAC SDN List. Chainalysis это делает автоматически, но для дополнительной защиты:
// Периодически обновляемый list OFAC адресов
const ofacAddresses = new Set(await fetchOFACList());
function isOFACSanctioned(address: string): boolean {
return ofacAddresses.has(address.toLowerCase());
}
Верификация возраста без документов
Для рынков где документальный KYC неприемлем (или до KYC tier), но нужна проверка возраста:
Yoti Age Verification — сервис, который верифицирует возраст без передачи document details казино. Пользователь проходит верификацию у Yoti, получает signed age token. Казино видит только "старше 18" — без имени, фото, номера документа.
AgeID (UK стандарт) — аналогичный подход, используется британскими gambling операторами.
Интеграция: OAuth 2.0 flow, Yoti выступает identity provider. Казино получает ID Token с клеймом over_18: true, без PII.
Геоблокировка и IP верификация
KYC не заменяет геоблокировку. Обязательные проверки:
async function checkPlayerEligibility(ip: string, walletAddress: string): Promise<EligibilityResult> {
// IP geolocation
const geoResult = await maxmindClient.country(ip);
const country = geoResult.country.isoCode;
if (BLOCKED_COUNTRIES.includes(country)) {
return { allowed: false, reason: 'geo_blocked', country };
}
// VPN/Proxy detection
const ipRisk = await ipqualityscore.check(ip);
if (ipRisk.vpn || ipRisk.proxy || ipRisk.tor) {
return { allowed: false, reason: 'vpn_detected' };
}
return { allowed: true, country };
}
Списки заблокированных стран определяются лицензией: Кюрасао, Мальта, Эстония — каждая лицензия имеет свой список restricted jurisdictions.
Responsible Gambling функции
Лицензированные казино обязаны реализовывать:
- Self-exclusion: пользователь может заблокировать собственный аккаунт на период (1 день до перманентного). После активации — немедленный logout, блок на re-registration.
- Deposit limits: дневные/недельные/месячные лимиты. Уменьшить можно сразу, увеличить — только через cooling-off period (24-72 часа).
- Reality check: всплывающее уведомление о времени и сумме потерь каждый N минут.
- Cooling-off period: временная пауза без полного самоисключения.
Стек и архитектура
| Компонент | Решение | Примечание |
|---|---|---|
| KYC провайдер | Sumsub / Onfido | Sumsub лучше для WW coverage |
| AML on-chain | Chainalysis KYT | или Elliptic, Crystal Blockchain |
| Age verification | Yoti / AgeID | для soft-KYC рынков |
| Geo/IP check | MaxMind + IPQualityScore | два провайдера для надёжности |
| OFAC/Sanctions | Chainalysis + собственный list | обновление ежедневно |
| Document storage | Encrypted S3 + key management | retention policy по регуляции |
Сроки разработки
| Компонент | Срок |
|---|---|
| KYC tier system + Sumsub интеграция | 2-3 нед |
| AML screening + webhook обработка | 1-2 нед |
| Геоблокировка + IP проверки | 1 нед |
| Responsible gambling функции | 1-2 нед |
| Admin dashboard для compliance | 1-2 нед |
Полная compliance система под конкретную лицензию — 6-10 недель. Стоимость зависит от выбранных провайдеров и объёма кастомизации.







