사전 요구사항
API 설정
| 설정 | 값 |
|---|---|
| Base URL | https://api.chainstream.io/ |
| Auth Domain | dex.asia.auth.chainstream.io |
| Audience | https://api.dex.chainstream.io |
KYT 관련 스코프
| 스코프 | 설명 |
|---|---|
kyt.read | KYT API 읽기 권한 (거래 리스크 조회) |
kyt.write | KYT API 쓰기 권한 (거래 분석 등록) |
액세스 토큰 생성
import { AuthenticationClient } from 'auth0';
const auth0Client = new AuthenticationClient({
domain: 'dex.asia.auth.chainstream.io',
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
});
// 전체 KYT 권한으로 토큰 획득
const response = await auth0Client.oauth.clientCredentialsGrant({
audience: 'https://api.dex.chainstream.io',
scope: 'kyt.read kyt.write'
});
const accessToken = response.data.access_token;
API 호출
모든 요청에 헤더에 토큰을 포함해야 합니다:const response = await fetch('https://api.chainstream.io/v1/kyt/transfer', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ /* 요청 본문 */ })
});
CEX 입금 리스크 관리
거래소 입금 시나리오는 KYT의 핵심 사용 사례로, 자금이 입금되기 전에 리스크 평가가 필요합니다.비즈니스 흐름
통합 단계
클라이언트 초기화
import { AuthenticationClient } from 'auth0';
// 토큰 생성 (캐싱 권장, 만료 전 갱신)
async function getAccessToken() {
const auth0Client = new AuthenticationClient({
domain: 'dex.asia.auth.chainstream.io',
clientId: process.env.CHAINSTREAM_CLIENT_ID,
clientSecret: process.env.CHAINSTREAM_CLIENT_SECRET
});
const { data } = await auth0Client.oauth.clientCredentialsGrant({
audience: 'https://api.dex.chainstream.io',
scope: 'kyt.read kyt.write'
});
return data.access_token;
}
거래 감지
사용자 입금 주소로의 수신 거래 모니터링:
async function onDepositDetected(tx) {
const deposit = {
network: 'ethereum', // 네트워크: bitcoin, ethereum, Solana
asset: tx.asset, // 자산 유형: ETH, SOL 등
transferReference: tx.hash, // 거래 해시
direction: 'received' // 방향: sent 또는 received
};
// KYT 분석 호출
const result = await registerTransfer(deposit);
// 리스크 평가 조회
const risk = await getTransferSummary(result.externalId);
// 결정 실행
await executeDecision(tx, risk);
}
거래 등록
KYT API 호출로 거래 등록:
async function registerTransfer(deposit) {
const response = await fetch('https://api.chainstream.io/v1/kyt/transfer', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
network: deposit.network,
asset: deposit.asset,
transferReference: deposit.transferReference,
direction: deposit.direction
})
});
return await response.json();
}
리스크 평가 조회
거래 리스크 요약 조회:
async function getTransferSummary(transferId) {
const response = await fetch(
`https://api.chainstream.io/v1/kyt/transfers/${transferId}/summary`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
return await response.json();
}
자동 결정
리스크 수준에 따라 적절한 조치 실행:
async function executeDecision(tx, risk) {
const riskLevel = risk.rating; // SEVERE, HIGH, MEDIUM, LOW
switch (riskLevel) {
case 'SEVERE':
await freezeDeposit(tx);
await createSARReport(tx, risk);
await notifyCompliance(tx, risk);
break;
case 'HIGH':
await holdDeposit(tx, { hours: 24 });
await createManualReview(tx, risk);
break;
case 'MEDIUM':
await creditDeposit(tx);
await flagForMonitoring(tx, risk);
break;
case 'LOW':
await creditDeposit(tx);
break;
}
// 감사 로그 기록
await auditLog.record({
action: 'DEPOSIT_RISK_DECISION',
txHash: tx.hash,
riskLevel,
timestamp: new Date()
});
}
전체 흐름 상세
엔드투엔드 컴플라이언스 통합 흐름: 감지 → 등록 → 폴링 → 리스크 판단 → 해제/동결1. 감지 단계
| 트리거 소스 | 설명 | 지연 시간 |
|---|---|---|
| 온체인 모니터링 | 입금 주소 모니터링 | 블록 컨펌 시간 |
| 사용자 제출 | 출금 요청 | 즉시 |
| 스케줄 스캔 | 캐치업 메커니즘 | 설정 가능 |
2. 등록 단계
POST https://api.chainstream.io/v1/kyt/transfer
Authorization: Bearer <access_token>
Content-Type: application/json
{
"network": "ethereum",
"asset": "ETH",
"transferReference": "0x1234567890abcdef...",
"direction": "received"
}
{
"externalId": "123e4567-e89b-12d3-a456-426614174000",
"asset": "ETH",
"network": "ethereum",
"transferReference": "0x1234567890abcdef...",
"direction": "received",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
3. 조회 단계
- 폴링 방식
- 상세 정보 조회
async function pollForResult(transferId, maxAttempts = 10) {
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.chainstream.io/v1/kyt/transfers/${transferId}/summary`,
{
headers: { 'Authorization': `Bearer ${accessToken}` }
}
);
const data = await response.json();
if (data.rating) {
return data;
}
await new Promise(r => setTimeout(r, 3000)); // 3초 간격
}
throw new Error('Analysis timeout');
}
리스크 노출 상세 정보 조회:
// 직접 리스크 노출 조회
const exposures = await fetch(
`https://api.chainstream.io/v1/kyt/transfers/${transferId}/exposures/direct`,
{ headers: { 'Authorization': `Bearer ${accessToken}` } }
);
// 리스크 알림 조회
const alerts = await fetch(
`https://api.chainstream.io/v1/kyt/transfers/${transferId}/alerts`,
{ headers: { 'Authorization': `Bearer ${accessToken}` } }
);
4. 판단 단계
리스크 판단 규칙 설정:risk_rules:
severe:
action: FREEZE
auto_execute: true
notify:
- compliance@company.com
- security@company.com
high:
action: MANUAL_REVIEW
auto_execute: false
hold_period: 24h
escalation: 4h
medium:
action: FLAG
auto_execute: true
monitoring_period: 30d
low:
action: PASS
auto_execute: true
5. 실행 단계
| 조치 | 트리거 조건 | 후속 조치 |
|---|---|---|
| 해제 | LOW 리스크 | 정상 입금/결제 |
| 플래그 | MEDIUM 리스크 | 입금하되 모니터링 지속 |
| 보류 | HIGH 리스크 | 수동 검토 대기열 진입 |
| 동결 | SEVERE 리스크 | 동결 + 컴플라이언스 보고 |
전체 서비스 구현
import { AuthenticationClient } from 'auth0';
class ComplianceService {
constructor() {
this.accessToken = null;
this.tokenExpiry = null;
}
// 토큰 획득 또는 갱신
async getAccessToken() {
if (this.accessToken && this.tokenExpiry > Date.now()) {
return this.accessToken;
}
const auth0Client = new AuthenticationClient({
domain: 'dex.asia.auth.chainstream.io',
clientId: process.env.CHAINSTREAM_CLIENT_ID,
clientSecret: process.env.CHAINSTREAM_CLIENT_SECRET
});
const { data } = await auth0Client.oauth.clientCredentialsGrant({
audience: 'https://api.dex.chainstream.io',
scope: 'kyt.read kyt.write'
});
this.accessToken = data.access_token;
// 토큰은 보통 24시간 유효, 1시간 전에 갱신
this.tokenExpiry = Date.now() + (23 * 60 * 60 * 1000);
return this.accessToken;
}
// 입금 컴플라이언스 확인
async checkDeposit(deposit) {
const token = await this.getAccessToken();
// 1. 거래 등록
const registerResponse = await fetch('https://api.chainstream.io/v1/kyt/transfer', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
network: deposit.network,
asset: deposit.asset,
transferReference: deposit.txHash,
direction: 'received'
})
});
const registered = await registerResponse.json();
// 2. 리스크 평가 대기 및 조회
const risk = await this.waitForAnalysis(token, registered.externalId);
// 3. 결정 생성
const decision = this.makeDecision(risk);
// 4. 감사 기록
await this.auditLog(deposit, risk, decision);
return decision;
}
async waitForAnalysis(token, transferId, maxAttempts = 10) {
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.chainstream.io/v1/kyt/transfers/${transferId}/summary`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const result = await response.json();
if (result.rating) {
return result;
}
await new Promise(r => setTimeout(r, 3000));
}
throw new Error('Analysis timeout');
}
makeDecision(risk) {
const decisions = {
'SEVERE': {
action: 'FREEZE',
requireSAR: true,
notify: ['compliance@company.com', 'security@company.com']
},
'HIGH': {
action: 'HOLD',
requireReview: true,
holdHours: 24
},
'MEDIUM': {
action: 'PASS',
flagMonitoring: true
},
'LOW': {
action: 'PASS'
}
};
return decisions[risk.rating] || decisions['LOW'];
}
async auditLog(deposit, risk, decision) {
console.log({
timestamp: new Date().toISOString(),
type: 'COMPLIANCE_CHECK',
deposit,
risk,
decision
});
}
}
// 사용 예시
const compliance = new ComplianceService();
app.post('/deposit/process', async (req, res) => {
const deposit = req.body;
const decision = await compliance.checkDeposit(deposit);
res.json(decision);
});
CEX 출금 리스크 관리
출금 시나리오에서는 사용자가 출금을 요청할 때 대상 주소의 리스크를 확인해야 합니다.비즈니스 흐름
구현 예시
async function handleWithdrawal(request) {
const { toAddress } = request;
const token = await complianceService.getAccessToken();
// 1. 주소 등록
const registerResponse = await fetch('https://api.chainstream.io/v1/kyt/address', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ address: toAddress })
});
await registerResponse.json();
// 2. 주소 리스크 조회
const riskResponse = await fetch(
`https://api.chainstream.io/v1/kyt/addresses/${toAddress}/risk`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const addressRisk = await riskResponse.json();
// 3. 리스크 처리
switch (addressRisk.rating) {
case 'SEVERE':
return {
status: 'REJECTED',
reason: 'Target address is associated with known criminal activity',
riskLevel: 'SEVERE'
};
case 'HIGH':
return {
status: 'PENDING_CONFIRMATION',
warning: 'This address has been flagged as high risk',
riskDetails: addressRisk,
requiresConfirmation: true
};
default:
return {
status: 'APPROVED',
riskLevel: addressRisk.rating
};
}
}
// Express 라우트 예시
app.post('/withdraw/request', async (req, res) => {
const result = await handleWithdrawal(req.body);
res.json(result);
});
지갑 리스크 알림
지갑 애플리케이션에서 사용자가 전송을 시작하기 전에 리스크 알림을 제공합니다.사용자 경험 흐름
프론트엔드/백엔드 통합
프론트엔드에서 clientSecret을 직접 노출하지 마세요. 백엔드 API 프록시를 사용하여 ChainStream을 호출하세요.
- 프론트엔드 호출
- 백엔드 프록시
// 주소 입력 변경 시 트리거
async function onAddressChange(address) {
if (!isValidAddress(address)) return;
setLoading(true);
try {
// 백엔드 프록시 API 호출
const response = await fetch('/api/risk/check-address', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ address })
});
const risk = await response.json();
setRiskInfo({
level: risk.rating,
labels: risk.labels,
warnings: risk.warnings
});
} finally {
setLoading(false);
}
}
app.post('/api/risk/check-address', async (req, res) => {
const { address } = req.body;
const token = await complianceService.getAccessToken();
// 주소 등록
await fetch('https://api.chainstream.io/v1/kyt/address', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ address })
});
// 리스크 조회
const riskResponse = await fetch(
`https://api.chainstream.io/v1/kyt/addresses/${address}/risk`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const result = await riskResponse.json();
res.json({
rating: result.rating,
riskScore: result.riskScore,
labels: result.labels || [],
warnings: generateWarnings(result)
});
});
function generateWarnings(result) {
const warnings = [];
if (result.exposures?.direct?.severe > 0) {
warnings.push('알려진 범죄 주소와 직접 연관됨');
}
if (result.labels?.includes('Mixer User')) {
warnings.push('믹싱 서비스와 상호작용한 이력 있음');
}
return warnings;
}
일괄 주소 스크리닝
엔터프라이즈 수준의 기존 주소 컴플라이언스 스크리닝.사용 사례
- 정기 컴플라이언스 감사
- 새로운 규제 요구사항 적용
- M&A 실사
- 리스크 스크리닝
일괄 스크리닝 구현
async function batchScreenAddresses(addresses) {
const token = await complianceService.getAccessToken();
const results = [];
for (const address of addresses) {
try {
// 주소 등록
await fetch('https://api.chainstream.io/v1/kyt/address', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ address })
});
// 리스크 조회
const riskResponse = await fetch(
`https://api.chainstream.io/v1/kyt/addresses/${address}/risk`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const risk = await riskResponse.json();
results.push({
address,
rating: risk.rating,
riskScore: risk.riskScore
});
} catch (error) {
results.push({
address,
error: error.message
});
}
}
// 고위험 주소 처리
const highRiskAddresses = results.filter(
r => r.rating === 'SEVERE' || r.rating === 'HIGH'
);
return { all: results, highRisk: highRiskAddresses };
}
모범 사례
임계값 설정 권장
비즈니스 유형에 따라 리스크 임계값을 조정하세요:| 비즈니스 유형 | SEVERE 처리 | HIGH 처리 | MEDIUM 처리 |
|---|---|---|---|
| 인가된 CEX | 자동 동결 | 수동 검토 | 모니터링 플래그 |
| 지갑 앱 | 강한 경고 | 경고 | 알림 |
| DeFi 프로토콜 | 상호작용 거절 | 경고 | 정상 |
| OTC 플랫폼 | 거래 거절 | 추가 KYC | 정상 |
감사 로그 요구사항
완전한 감사 추적 보장:{
"eventId": "evt_123456",
"timestamp": "2024-01-15T10:30:00Z",
"eventType": "RISK_DECISION",
"subject": {
"transferId": "123e4567-e89b-12d3-a456-426614174000",
"txHash": "0x...",
"userId": "user_789"
},
"riskAssessment": {
"rating": "HIGH",
"riskScore": 72
},
"decision": {
"action": "HOLD",
"decidedBy": "SYSTEM",
"reason": "Auto-hold per risk policy"
},
"metadata": {
"policyVersion": "1.2.0",
"engineVersion": "2024.01"
}
}
다음 단계
인증 문서
상세 인증 가이드
KYT 개념
KYT 핵심 개념
KYA 개념
KYA 핵심 개념
KYT API 레퍼런스
KYT API 전체 문서

