Интеграция с Chainalysis для мониторинга транзакций
Chainalysis KYT (Know Your Transaction) — индустриальный стандарт для мониторинга криптотранзакций. Ключевое преимущество: Chainalysis строит graphy всей блокчейн истории, не просто проверяет прямую транзакцию — отслеживает средства через несколько хопов (indirect exposure).
KYT API архитектура
Chainalysis KYT v2 API работает по модели: регистрируем пользователей и переводы, получаем risk данные. Два режима: synchronous (immediate response) и asynchronous (webhook callback для сложных случаев).
class ChainalysisKYTService {
private readonly API_BASE = "https://api.chainalysis.com/api/kyt/v2";
// Регистрация нового кошелька пользователя
async registerUser(userId: string, asset: string): Promise<void> {
await this.apiCall("POST", "/users", { userId, asset });
}
// Скрининг входящего перевода (депозит)
async registerReceivedTransfer(params: {
network: string;
asset: string;
transferReference: string; // txHash для on-chain, или external ID
userId: string;
outputAddress: string;
assetAmount: number;
timestamp: string; // ISO 8601
}): Promise<ReceivedTransferResponse> {
return this.apiCall("POST", "/transfers/received", {
network: params.network,
asset: params.asset,
transferReference: params.transferReference,
userId: params.userId,
outputAddress: params.outputAddress,
assetAmount: params.assetAmount,
timestamp: params.timestamp,
});
}
// Скрининг исходящего перевода (вывод)
async registerSentTransfer(params: {
network: string;
asset: string;
transferReference: string;
userId: string;
outputAddress: string;
assetAmount: number;
}): Promise<SentTransferResponse> {
return this.apiCall("POST", "/transfers/sent", params);
}
// Получение alerts по переводу
async getTransferAlerts(externalId: string): Promise<Alert[]> {
const response = await this.apiCall("GET", `/transfers/${externalId}/alerts`);
return response.alerts;
}
private async apiCall(method: string, path: string, body?: any): Promise<any> {
const response = await fetch(`${this.API_BASE}${path}`, {
method,
headers: {
"Token": this.apiKey,
"Content-Type": "application/json",
"Accept": "application/json",
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
const error = await response.json();
throw new ChainalysisError(response.status, error.message);
}
return response.json();
}
}
Обработка risk response
interface KYTRiskResponse {
externalId: string;
asset: string;
network: string;
transferReference: string;
updatedAt: string;
status: "APPROVED" | "BLOCKED" | "IN_REVIEW";
cluster: {
name: string;
category: string; // "darknet_market", "exchange", "sanctions", etc.
} | null;
riskScore: number; // 0-100
}
async function handleDepositScreening(deposit: Deposit): Promise<void> {
const response = await chainalysis.registerReceivedTransfer({
network: deposit.blockchain,
asset: deposit.token,
transferReference: deposit.txHash,
userId: deposit.userId,
outputAddress: deposit.toAddress,
assetAmount: deposit.amount,
timestamp: deposit.timestamp.toISOString(),
});
// Ждём обработки (обычно 1-30 секунд)
const riskData = await pollForResult(response.externalId);
if (riskData.status === "BLOCKED" || riskData.riskScore >= 70) {
await db.freezeDeposit(deposit.id, riskData.riskScore, riskData.cluster?.category);
await alertComplianceTeam({
depositId: deposit.id,
userId: deposit.userId,
riskScore: riskData.riskScore,
category: riskData.cluster?.category,
externalId: response.externalId,
});
return;
}
if (riskData.status === "IN_REVIEW" || riskData.riskScore >= 40) {
await db.holdForManualReview(deposit.id, riskData.riskScore);
await createComplianceTask(deposit, riskData);
return;
}
await db.approveDeposit(deposit.id);
await creditUserBalance(deposit);
}
Webhook для async results
Chainalysis присылает webhook при завершении анализа:
app.post("/webhooks/chainalysis", async (req, res) => {
const { externalId, asset, updatedAt, status, riskScore, cluster, alerts } = req.body;
// Находим pending транзакцию
const deposit = await db.findDepositByExternalId(externalId);
if (!deposit) return res.status(404).send();
if (status === "BLOCKED" || riskScore >= 70) {
await db.freezeDeposit(deposit.id, riskScore, cluster?.category);
await alertCompliance(deposit, { riskScore, cluster, alerts });
} else if (status === "IN_REVIEW") {
await createManualReviewTask(deposit, { riskScore, alerts });
} else {
await approveDeposit(deposit.id);
}
res.status(200).send();
});
Alert категории и правила обработки
| Категория | Действие |
|---|---|
| sanctions | Блокировка + немедленный алерт compliance |
| darknet_market | Блокировка + SAR draft |
| ransomware | Блокировка + SAR draft |
| stolen_funds | Блокировка |
| mixing / tumbling | Review + Enhanced Monitoring |
| p2p_exchange | Review (зависит от volume) |
| gambling | Review (зависит от лицензии) |
| exchange | Обычно пропустить |
Интеграция Chainalysis KYT для мониторинга депозитов и выводов с webhook обработкой и compliance alerting — 1-2 недели разработки.







