メインコンテンツへスキップ
本ガイドでは、ChainStream の KYT/KYA コンプライアンス機能をアプリケーションに組み込む方法を説明します。CEX の入出金リスク管理、ウォレットのリスクアラート、一括スクリーニングまで、一連のシナリオをカバーします。

前提条件

API 設定

設定項目
Base URLhttps://api.chainstream.io/
Auth Domaindex.asia.auth.chainstream.io
Audiencehttps://api.dex.chainstream.io

KYT 関連スコープ

スコープ説明
kyt.readKYT API の読み取り権限(取引リスクの照会)
kyt.writeKYT API の書き込み権限(取引分析の登録)

アクセストークンの取得

import { AuthenticationClient } from 'auth0';

const auth0Client = new AuthenticationClient({
  domain: 'dex.asia.auth.chainstream.io',
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret'
});

// Get Token with full KYT permissions
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({ /* request body */ })
});

CEX 入金時のリスク管理

取引所の入金シナリオは KYT の中核ユースケースであり、資金を計上する前にリスク評価が必要です。

業務フロー

連携手順

1

クライアントの初期化

import { AuthenticationClient } from 'auth0';

// Generate Token (recommend caching, refresh before expiry)
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;
}
2

取引の検知

ユーザーの入金アドレスへの着金を監視します。
async function onDepositDetected(tx) {
  const deposit = {
    network: 'ethereum',           // Network: bitcoin, ethereum, Solana
    asset: tx.asset,               // Asset type: ETH, SOL, etc.
    transferReference: tx.hash,    // Transaction hash
    direction: 'received'          // Direction: sent or received
  };
  
  // Call KYT analysis
  const result = await registerTransfer(deposit);
  
  // Get risk assessment
  const risk = await getTransferSummary(result.externalId);
  
  // Execute decision
  await executeDecision(tx, risk);
}
3

取引の登録

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();
}
4

リスク評価の取得

取引のリスクサマリーを照会します。
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();
}
5

自動判定

リスクレベルに応じた処理を実行します。
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;
  }
  
  // Record audit log
  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 second interval
  }
  
  throw new Error('Analysis timeout');
}

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;
  }

  // Get or refresh Token
  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;
    // Token usually valid 24 hours, refresh 1 hour early
    this.tokenExpiry = Date.now() + (23 * 60 * 60 * 1000);
    
    return this.accessToken;
  }

  // Deposit compliance check
  async checkDeposit(deposit) {
    const token = await this.getAccessToken();
    
    // 1. Register transaction
    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. Wait and get risk assessment
    const risk = await this.waitForAnalysis(token, registered.externalId);
    
    // 3. Generate decision
    const decision = this.makeDecision(risk);
    
    // 4. Record audit
    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
    });
  }
}

// Usage example
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. Register address
  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. Get address risk
  const riskResponse = await fetch(
    `https://api.chainstream.io/v1/kyt/addresses/${toAddress}/risk`,
    { headers: { 'Authorization': `Bearer ${token}` } }
  );
  const addressRisk = await riskResponse.json();
  
  // 3. Risk handling
  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 route example
app.post('/withdraw/request', async (req, res) => {
  const result = await handleWithdrawal(req.body);
  res.json(result);
});

ウォレットのリスクアラート

ウォレットアプリでは、ユーザーが送金する前にリスクアラートを表示します。

ユーザー体験フロー

フロントエンド/バックエンド連携

フロントエンドに clientSecret を直接置かないでください。ChainStream 呼び出しはバックエンド API 経由のプロキシにしてください。
// Trigger on address input change
async function onAddressChange(address) {
  if (!isValidAddress(address)) return;
  
  setLoading(true);
  
  try {
    // Call backend proxy 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);
  }
}

アドレスの一括スクリーニング

既存アドレスに対するエンタープライズ向けコンプライアンス一括チェックです。

ユースケース

  • 定期的なコンプライアンス監査
  • 新たな規制要件への対応
  • M&A のデューデリジェンス
  • リスクスクリーニング

一括スクリーニングの実装

async function batchScreenAddresses(addresses) {
  const token = await complianceService.getAccessToken();
  const results = [];
  
  for (const address of addresses) {
    try {
      // Register address
      await fetch('https://api.chainstream.io/v1/kyt/address', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ address })
      });
      
      // Get risk
      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
      });
    }
  }
  
  // Process high-risk addresses
  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 の完全ドキュメント