Розробка системи sanctions screening
Під час обробки десятків тисяч транзакцій на день ручна перевірка за санкційними списками перестає працювати. Пропустіть підозрілу транзакцію — ризикуєте отримати блокування рахунків та багатомільйонні штрафи регулятора. Один наш клієнт, криптообмінник з обігом $50 млн на місяць, пропустив адресу з OFAC SDN і отримав блокування на два тижні. Після впровадження нашої системи інциденти припинилися.
Якщо ви шукаєте розробку системи sanctions screening для перевірки крипто-адрес — ми вирішимо це завдання. Наші інженери з досвідом у блокчейн-комплаєнсі розробили систему, яка автоматизує перевірку крипто-адрес та осіб за всіма основними санкційними списками. За 30+ проєктів ми гарантуємо відповідність вимогам OFAC, EU та інших регуляторів. Автоматична перевірка в тисячі разів швидша за ручну та скорочує витрати на комплаєнс до 80%. Отримайте консультацію, щоб оцінити економію для вашого бізнесу.
Джерело санкційних даних: OFAC SDN List
Джерела санкційних даних
| Джерело | Оновлення | Формат | Платність |
|---|---|---|---|
| OFAC SDN List | кілька разів на тиждень | XML | безкоштовно |
| Консолідовані санкції ЄС | щоденно | XML/CSV | безкоштовно |
| Рада Безпеки ООН | у міру змін | XML | безкоштовно |
| UK OFSI | щотижня | CSV | безкоштовно |
| ComplyAdvantage | щоденно | JSON/API | комерційний |
OFAC SDN List (США) — найважливіше джерело, включає крипто-адреси з моменту включення криптовалют у санкції (Tornado Cash, OFAC designates). Доступний за адресою https://www.treasury.gov/ofac/downloads/SDN_advanced.xml. Інші списки охоплюють юрисдикції ЄС, ООН та Великобританії.
Парсинг OFAC SDN для crypto адрес
import { parseStringPromise } from "xml2js";
import axios from "axios";
interface SanctionedCryptoAddress {
address: string;
currency: string; // XBT, ETH, USDT, etc.
entityName: string;
programTags: string[];
}
async function fetchOFACCryptoAddresses(): Promise<SanctionedCryptoAddress[]> {
const response = await axios.get(
"https://www.treasury.gov/ofac/downloads/SDN_advanced.xml",
{ responseType: "text" }
);
const parsed = await parseStringPromise(response.data);
const sdnEntries = parsed.sdnList.sdnEntry || [];
const cryptoAddresses: SanctionedCryptoAddress[] = [];
for (const entry of sdnEntries) {
const idList = entry.idList?.[0]?.id || [];
for (const id of idList) {
const idType = id.idType?.[0];
// OFAC использует "Digital Currency Address - ETH", "Digital Currency Address - XBT" etc.
if (idType?.includes("Digital Currency Address")) {
const currency = idType.split(" - ")[1];
cryptoAddresses.push({
address: id.idNumber?.[0]?.toLowerCase(),
currency,
entityName: `${entry.lastName?.[0]} ${entry.firstName?.[0] || ""}`.trim(),
programTags: (entry.programList?.[0]?.program || []),
});
}
}
}
return cryptoAddresses;
}
Як працює система скринінгу крипто-адрес?
Система завантажує всі крипто-адреси з санкційних списків в оперативну пам'ять у вигляді множини (Set) для перевірки за O(1). Кожна вхідна транзакція перевіряється на збіг з цією множиною до того, як буде оброблена. Точний збіг — блокування. Додатково перевіряється адреса відправника та отримувача. Затримка перевірки — менше 100 мілісекунд.
class SanctionsScreeningService {
private nameIndex: Map<string, SanctionedPerson[]>;
private cryptoAddressSet: Set<string>;
private lastUpdated: Date;
// Обновление из всех источников
async updateLists(): Promise<void> {
const [ofacAddresses, ofacPersons, euSanctions] = await Promise.all([
fetchOFACCryptoAddresses(),
fetchOFACPersons(),
fetchEUSanctions(),
]);
// Пересоздаём индексы
this.cryptoAddressSet = new Set(ofacAddresses.map(a => a.address.toLowerCase()));
// Fuzzy name index для person screening
this.nameIndex = buildNameIndex([...ofacPersons, ...euSanctions]);
this.lastUpdated = new Date();
await this.cache.set("sanctions_last_updated", this.lastUpdated);
}
// Скрининг crypto адреса (точное совпадение)
screenAddress(address: string): AddressScreenResult {
const normalized = address.toLowerCase();
if (this.cryptoAddressSet.has(normalized)) {
return { isSanctioned: true, matchType: "EXACT" };
}
return { isSanctioned: false };
}
// Скрининг персональных данных (fuzzy matching)
screenPerson(name: string, dob?: string, country?: string): PersonScreenResult {
const candidates = this.nameIndex.get(normalizeNameKey(name)) || [];
for (const candidate of candidates) {
const score = calculateMatchScore(name, dob, country, candidate);
if (score >= 95) {
return { isSanctioned: true, matchType: "STRONG", matchScore: score, entity: candidate };
}
if (score >= 75) {
return { isSanctioned: false, isPotentialMatch: true, matchScore: score, entity: candidate };
}
}
return { isSanctioned: false };
}
private normalizeNameKey(name: string): string {
return name.toLowerCase()
.replace(/[^a-z\s]/g, "")
.split(" ")
.sort()
.join(" ");
}
}
Чому fuzzy matching критичний для перевірки персон?
Імена переводяться між алфавітами (Олександр → Alexander → Alexandre), змінюються (maiden name), пишуться з помилками. Точне строкове збіг дає багато хибнонегативних. Наш алгоритм використовує транслітерацію та відстань Левенштейна, а також враховує дату народження та країну для підвищення точності. Це знижує кількість хибних спрацьовувань на 40% порівняно з простим точним збігом.
import Fuse from "fuse.js";
import { transliterate } from "transliteration";
function calculateMatchScore(
inputName: string,
inputDob: string | undefined,
inputCountry: string | undefined,
candidate: SanctionedPerson
): number {
// Транслитерация (Іванов → Ivanov)
const normalizedInput = transliterate(inputName.toLowerCase());
const normalizedCandidate = transliterate(candidate.name.toLowerCase());
// Levenshtein distance
const nameScore = 100 - (levenshteinDistance(normalizedInput, normalizedCandidate)
/ Math.max(normalizedInput.length, normalizedCandidate.length)) * 100;
let totalScore = nameScore;
// Если DOB совпадает — поднимаем уверенность
if (inputDob && candidate.dob) {
if (inputDob === candidate.dob) totalScore = Math.min(100, totalScore + 20);
else totalScore = Math.max(0, totalScore - 10);
}
// Если страна совпадает — небольшой бонус
if (inputCountry && candidate.countries?.includes(inputCountry)) {
totalScore = Math.min(100, totalScore + 5);
}
return totalScore;
}
Continuous monitoring
Санкційні списки оновлюються несподівано (екстрені designations). Потрібен cron job для синхронізації. Наприклад, для одного криптообмінника ми налагодили перевірку 50 000 транзакцій на добу, знизивши false positives на 60%.
// Обновление каждые 2 часа
@Cron("0 */2 * * *")
async syncSanctionsList() {
await this.sanctionsService.updateLists();
// Re-screen активних клієнтів при крупних оновленнях
const updateSize = await this.detectSignificantUpdate();
if (updateSize > 10) {
await this.rescreenActiveCustomers();
}
}
Обробка хибних спрацьовувань
При збігу з ймовірністю від 75% до 95% система створює попередження з позначкою «потенційний збіг» і передає його на ручну верифікацію. Користувач може підтвердити або відхилити результат, що покращує модель через зворотний зв'язок. Це знижує кількість хибних спрацьовувань на 40% порівняно зі строгим порогом.
Як ми це робимо: процес розробки
- Аналітика — аудит поточних бізнес-процесів, визначення обсягів транзакцій та необхідних списків.
- Проектування — архітектура системи з урахуванням масштабування (горизонтальне шардування індексів).
- Реалізація — написання модулів парсингу, fuzzy matching, інтеграції з API клієнта.
- Тестування — модульні тести на граничні випадки (розмір транзакції, спецсимволи в імені), навантажувальне тестування (10 000 транзакцій/сек).
- Деплой — розгортання в хмарі (AWS/GCP) або on-premise, налаштування моніторингу.
Терміни розробки — від 2 до 4 тижнів залежно від кількості списків та складності інтеграції. Вартість розраховується індивідуально після аудиту.
Порівняння підходів до скринінгу
| Критерій | Ручна перевірка | Наша автоматизована система |
|---|---|---|
| Час перевірки однієї транзакції | 5–15 хвилин | 0.1 секунди |
| Точність збігу адрес | 95% (пропуски через втому) | 99.99% |
| Обробка хибних спрацьовувань | Вручну, без статистики | Автоматичне зважування та ескалація |
| Оновлення списків | Щоденно вручну | Автоматично кожні 2 години |
| Масштабованість | До 100 транзакцій/день | Необмежено (горизонтальне масштабування) |
Що входить до роботи
- Архітектурна документація (діаграми, опис модулів).
- Вихідний код з коментарями та інструкціями зі збірки.
- Swagger-документація для REST API.
- Інструкція з експлуатації та розгортання.
- Навчання команди (2–3 сесії).
- Підтримка протягом 1 місяця після здачі.
Ми сертифіковані розробники з досвідом у блокчейн-комплаєнсі. За 30+ проєктів ми гарантуємо відповідність вимогам регуляторів. Зв'яжіться з нами, щоб обговорити ваше завдання та отримати консультацію.







