21. AML · Travel Rule
Step 5b/5c — AML provider 통합 · incoming reject 처리AML Provider 통합 (★ Stage 9 명시)
transaction-lifecycle.md, p.4 diagram 에서 정식 명시된 AML provider:
- Chainalysis
- Elliptic
- Notabene
14-step Flow 내 위치
- Step 5b: Transaction Manager → Screening Service → AML Provider
- Step 5c: Transaction Manager → Screening Service → Travel Rule Provider
- 두 검증 모두 통과 후에야 Policy Engine (Step 6) 진입
AML Policy 의 평면 분리
Fireblocks Policy 와 별개 평면 (security-checklist.md):
- Fireblocks Policies (TAP): 일반 tx 단위 rule
- AML Transaction Screening Policy: AML provider 통합 — 별도 종류
- DCCP: confirmation 정책 — 또 다른 종류
Workspace-level AML Default (★ Stage 9)
vault-structure-best-practices.md, p.5-6: Multi-workspace 가 필요한 이유 중 하나로 다른 AML default 명시:
- fail-on-unknown: 모르는 destination 은 차단
- pass-on-unknown: 모르는 destination 은 통과
Incoming Reject 의 Lock 상태 (★)
primary-transaction-statuses.md, p.8:
Outgoing vs Incoming Rejected 차이
- Outgoing rejected: 자산 즉시 사용 가능 (re-tx 가능)
- Incoming rejected: 자산이 Admin 가 unfreeze 할 때까지 사용 불가
변경 거버넌스
user-roles.md, p.7-8 권한표:
- Add or modify AML connections and policies: Owner / Admin / NSA ✓
- Add or modify Travel Rule connections and policies: Owner / Admin / NSA ✓
DB Schema
CREATE TABLE aml_providers (
id BINARY(16) PRIMARY KEY,
workspace_id BINARY(16) NOT NULL,
provider_name ENUM('chainalysis', 'elliptic', 'notabene') NOT NULL,
endpoint_url VARCHAR(255) NOT NULL,
api_credential_hsm_keyref VARCHAR(128) NOT NULL, -- ★ HSM-wrapped, never plaintext
default_policy ENUM('fail-on-unknown', 'pass-on-unknown') NOT NULL,
enabled_at DATETIME(6) NOT NULL,
disabled_at DATETIME(6),
UNIQUE KEY (workspace_id, provider_name)
);
-- ★ append-only
CREATE TABLE aml_screening_results (
id BINARY(16) PRIMARY KEY,
transaction_id BINARY(16) NOT NULL,
provider_id BINARY(16) NOT NULL,
direction ENUM('incoming', 'outgoing') NOT NULL,
risk_score DECIMAL(5, 2),
decision ENUM('allow', 'block', 'manual-review') NOT NULL,
raw_response_cbor BLOB NOT NULL, -- vendor response 보존
screened_at DATETIME(6) NOT NULL,
KEY (transaction_id),
KEY (provider_id, screened_at)
);
-- ★ append-only — Travel Rule message 보존 (counterparty exchange)
CREATE TABLE travel_rule_records (
id BINARY(16) PRIMARY KEY,
transaction_id BINARY(16) NOT NULL,
provider_id BINARY(16) NOT NULL,
direction ENUM('outbound', 'inbound') NOT NULL,
originator_info_cbor BLOB NOT NULL, -- VASP info
beneficiary_info_cbor BLOB NOT NULL,
vasp_message_id VARCHAR(128),
status ENUM('pending', 'sent', 'acked', 'rejected') NOT NULL,
exchanged_at DATETIME(6) NOT NULL,
KEY (transaction_id)
);
-- Incoming reject 의 asset lock 추적
CREATE TABLE rejected_incoming_assets (
id BINARY(16) PRIMARY KEY,
transaction_id BINARY(16) NOT NULL UNIQUE,
asset_wallet_id BINARY(16) NOT NULL,
amount_decimal DECIMAL(38, 18) NOT NULL,
rejected_at DATETIME(6) NOT NULL,
unfreeze_attempts INT NOT NULL DEFAULT 0,
unfrozen_at DATETIME(6), -- ★ set-once
unfrozen_by_user_id BINARY(16), -- Admin
KEY (asset_wallet_id, unfrozen_at)
);
FSPM (Fireblocks Security Posture Management)
Security Auditor / Security Admin 의 권한 영역. Security Center 화면 + findings 관리. 정확한 entity-grade 명세는 Fireblocks 자료 부족 — Q-S07 Open Question.