Skill: npc7/amlclaw (version 2.0.0)

--- name: amlclaw description: "AI-powered crypto AML compliance toolkit. Screens blockchain addresses against 40+ international regulations, generates compliance policies, and creates machine-readable detection rules. Covers Singapore MAS, Hong Kong SFC, Dubai VARA, FATF, OFAC sanctions. Ships with pre-built rulesets and policies — works out of the box. Use when: screening addresses, generating AML rules, creating compliance policies, investigating crypto transactions, or when user mentions 'AML', 'compliance', 'screen address', 'KYA', 'rules'." argument-hint: "[screen|rules|policy] [options]" allowed-tools: Bash(python3 *), Read, Write, Edit, Glob, Grep, WebSearch --- # AMLClaw — AI-Powered Crypto AML Compliance You are an Expert AML Compliance Agent. This skill provides three modes: **Screen** addresses, **Generate** rules, and **Create** policies. All work out of the box with included defaults. ## Quick Start ```bash pip install requests python-dotenv cp amlclaw/defaults/rulesets/singapore_mas.json ./rules.json python3 amlclaw/scripts/run_screening.py Tron <ADDRESS> --scenario deposit --inflow-hops 3 --outflow-hops 3 ``` ## Capabilities Overview | Mode | Command | Description | |------|---------|-------------| | **Screen** | `python3 amlclaw/scripts/run_screening.py ...` | Screen blockchain addresses against compliance rules | | **Rules** | Interactive rule generation | Create/edit machine-readable AML detection rules | | **Policy** | Generate from rules.json | Create formal compliance policy documents | ## Out-of-the-Box Defaults AMLClaw ships ready to use: - **3 Regional Rulesets**: `defaults/rulesets/singapore_mas.json`, `hong_kong_sfc.json`, `dubai_vara.json` - **3 Compliance Policies**: `defaults/policies/singapore_mas.md`, `hong_kong_sfc.md`, `dubai_vara.md` - **40+ Reference Documents**: FATF recommendations, MAS/SFC/VARA guides, OFAC/UN sanctions in `references/` - **TrustIn Label Taxonomy**: `references/trustin-labels.md` — all valid tag categories --- ## Mode 1: Address Screening ### Parameter Gathering Collect from the user (assume defaults if not specified): | Parameter | Required | Default | Description | |-----------|----------|---------|-------------| | Chain | Yes | — | Tron, Ethereum, Bitcoin, Solana | | Address | Yes | — | Blockchain wallet address | | Scenario | No | `all` | Business context filter (see table below) | | Direction | No | Auto from scenario | `inflow`, `outflow`, or `all` | | Inflow Hops | No | 3 | Depth of inflow trace (1-5) | | Outflow Hops | No | 3 | Depth of outflow trace (1-5) | | Max Nodes | No | 100 | Branching factor per hop (max 1000) | | Time Window | No | Last 4 years | `--min-timestamp` / `--max-timestamp` in ms | ### Scenario Reference | Scenario | Rules Applied | Default Direction | Use Case | |----------|--------------|-------------------|----------| | `onboarding` | Deposit | all | KYC checks on new addresses | | `deposit` | Deposit | all | Screen fund sources + outflow history | | `withdrawal` | Withdrawal | outflow | Screen outgoing fund destinations | | `cdd` | CDD | all | Customer Due Diligence thresholds | | `monitoring` | Ongoing Monitoring | all | Continuous structuring/smurfing alerts | | `all` | ALL categories | all | Full comprehensive scan (default) | ### Pre-flight: Rules Check Before running, check for `./rules.json` in the working directory. - **If found**: Proceed with screening. - **If missing**: Do NOT block. Instead, auto-copy the closest regional default: ```bash cp amlclaw/defaults/rulesets/singapore_mas.json ./rules.json ``` Inform the user which default was loaded and continue. ### Execution ```bash python3 amlclaw/scripts/run_screening.py <Chain> <Address> \ --scenario <scenario> \ --inflow-hops <N> --outflow-hops <N> \ --max-nodes <N> ``` Examples: ```bash # Deposit screening python3 amlclaw/scripts/run_screening.py Tron THaUuZZ... --scenario deposit --inflow-hops 5 --outflow-hops 5 # Withdrawal screening python3 amlclaw/scripts/run_screening.py Ethereum 0xABC... --scenario withdrawal --outflow-hops 3 # Full scan python3 amlclaw/scripts/run_screening.py Tron THaUuZZ... --scenario all ``` ### Report Generation After the script completes: 1. Read `prompts/evaluation_prompt.md` for report format instructions 2. Read the generated `./graph_data/risk_paths_<address>_<timestamp>.json` 3. Cross-reference against `./rules.json` 4. Write the Markdown audit report to `./reports/aml_screening_<address>_<timestamp>.md` 5. Give the user a 2-3 sentence Executive Summary with risk score and key findings **Core Directive**: Never hallucinate risk data. Use only nodes, paths, and tags from the JSON graph. --- ## Mode 2: Rule Generation ### Input Options Present these to the user: 1. **Manual Input** — Type or paste rule descriptions directly 2. **Document Analysis** — Read policy documents from `references/` folder 3. **Web Search** — Search for latest regulations on a topic 4. **Load Default** — Copy a regional ruleset (Singapore MAS, Hong Kong SFC, Dubai VARA) ### Rule Categories Every rule belongs to exactly one category: | Category | Business Meaning | Condition Type | |----------|-----------------|----------------| | **Deposit** | Address risk: inflow sources, outflow history, self-tags | `path.node.*`, `target.tags.*` | | **Withdrawal** | Outflow risk: destination paths, self-tags | `path.node.*`, `target.tags.*` | | **CDD** | Transaction threshold triggers | `path.amount` | | **Ongoing Monitoring** | Continuous surveillance (structuring) | `target.daily_*` | ### Rule Structure Rules follow `schema/rule_schema.json`. Key fields: - `rule_id`: Unique identifier (e.g., `SG-DPT-DEP-SEVERE-001`) - `category`: One of the 4 categories above - `direction`: `"inflow"` or `"outflow"` (optional, omit for direction-agnostic) - `min_hops` / `max_hops`: Hop distance range (optional) - `conditions`: Array of conditions (AND logic) - `risk_level`: `Severe`, `High`, `Medium`, `Low` - `action`: `Freeze`, `EDD`, `Flag`, `Allow` **Tag values MUST match TrustIn taxonomy exactly** — see `references/trustin-labels.md`. ### Hop-Based Risk Tiering (Pollution Decay) - Hop 1 (direct) → Severe/Freeze - Hop 2-3 (near) → Severe/Freeze or High/EDD - Hop 4-5 (far) → High/EDD (reduced severity) ### Validation After every save to `rules.json`, run: ```bash python3 amlclaw/scripts/validate_rules.py rules.json ``` ### Rule CRUD Support these operations conversationally: - **List**: Show current rules in Markdown table - **Add**: Extract from text/docs/search → present → confirm → append - **Update**: Modify specific rule fields - **Delete**: Remove by rule_id --- ## Mode 3: Policy Generation Generate a formal AML compliance policy document from `rules.json`. ### Workflow 1. Read `./rules.json` 2. Transform rules into a professional compliance document: - Executive summary - Regulatory framework and jurisdiction - Risk categories and thresholds - Required procedures (KYC, CDD, EDD, STR filing) - Monitoring requirements - Escalation procedures 3. Output as Markdown — offer to save as `./aml_policy.md` ### Default Policies Pre-built policy documents are available in `defaults/policies/`: - `singapore_mas.md` — MAS PSN02/PSN08 compliance - `hong_kong_sfc.md` — SFC AMLO/AML Guidelines - `dubai_vara.md` — VARA Compliance & Risk Management Rules These can be used as templates or delivered directly. --- ## API Configuration **TrustIn KYA API** powers the blockchain data retrieval. | Mode | API Key | Data Quality | |------|---------|-------------| | **Free (default)** | Not required | Desensitized/masked addresses — sufficient for testing and development | | **Full** | Required | Complete unmasked data — for production compliance | - **Get a free key**: [trustin.info](https://trustin.info) - **Set via environment**: `export TRUSTIN_API_KEY=your_key` - **Set via flag**: `--api-key your_key` (on fetch_graph.py) - **Or**: Add to `.env` file in working directory --- ## References The `references/` folder contains 40+ regulatory documents: - `fatf/` — FATF 40 Recommendations, VA/VASP Guidance, Travel Rule - `singapore/` — MAS DPT compliance guide - `hongkong/` — SFC AML compliance guide - `dubai/` — VARA compliance guide - `sanctions/` — OFAC, FATF high-risk jurisdictions, UN sanctions - `trustin-labels.md` — Complete TrustIn tag taxonomy (required for rule authoring) ## Limitations - Single address per screening run (no batch) - No real-time monitoring — point-in-time assessment - Supported chains: Tron, Ethereum, Bitcoin, Solana (TrustIn coverage) - OR logic in rules requires separate rule entries - Generated policies are templates, not legal advice

path: CONTRIBUTING.md
content: # Contributing to AMLClaw

This guide is for AI agents (Claude Code, OpenClaw, etc.) contributing to this repo.

## Adding New Regulations

1. Place `.md` files in `references/<jurisdiction>/`
2. Follow naming convention: `<ID>-<Short-Title>.md` (e.g., `FATF-001-40-Recommendations-2025.md`)
3. Include source URL, effective date, and key provisions
4. Reference documents are used by agents to generate rulesets and policies

## Adding New Regional Rulesets

1. Create a JSON file in `defaults/rulesets/<jurisdiction>.json`
2. Follow the schema in `schema/rule_schema.json`
3. Each rule must have:
   - `rule_id`: Format `<COUNTRY>-<REGULATOR>-<CATEGORY>-<LEVEL>-<SEQ>` (e.g., `SG-DPT-DEP-SEVERE-001`)
   - `category`: One of `Deposit`, `Withdrawal`, `CDD`, `Ongoing Monitoring`
   - `conditions`: Array of parameter/operator/value objects
   - `risk_level`: `Severe`, `High`, `Medium`, or `Low`
   - `action`: `Freeze`, `Reject`, `EDD`, `Review`, `Allow`, or `Whitelist`
   - `reference`: Cite the specific regulation section
4. Use tag categories from `references/trustin-labels.md`

## Adding New Policy Documents

1. Create a `.md` file in `defaults/policies/<jurisdiction>.md`
2. Reference actual rule IDs from the corresponding ruleset
3. Cover: CDD/EDD, screening procedures, STR filing, record keeping, Travel Rule, sanctions, monitoring

## Validation

Before submitting, validate your ruleset:

```bash
python3 scripts/validate_rules.py defaults/rulesets/<your_file>.json
```

Validation must pass with zero errors.

## PR Expectations

- All rulesets validate cleanly
- Follow existing naming conventions and file structure
- Reference specific regulation sections (not generic citations)
- One jurisdiction per PR preferred
- Policy documents should reference rule IDs from the paired ruleset


path: README.md
content: # AMLClaw 🦅

AI-powered crypto AML compliance skill for coding agents.

Screen blockchain addresses, generate compliance rules, create policy documents — out of the box.

## Install

**OpenClaw:**
```bash
clawhub install amlclaw
```

**Claude Code:**
```bash
git clone https://github.com/amlclaw/amlclaw.git .claude/skills/amlclaw
```

**Any agent framework:**
```bash
git clone https://github.com/amlclaw/amlclaw.git ./skills/amlclaw
pip install -r skills/amlclaw/requirements.txt
```

One skill. Three capabilities. Zero configuration required.

## What's Included

| Asset | Path | Description |
|-------|------|-------------|
| Skill Definition | `SKILL.md` | Agent instructions — screen, generate rules, create policies |
| Rulesets (3) | `defaults/rulesets/` | Singapore MAS, Hong Kong SFC, Dubai VARA |
| Policies (3) | `defaults/policies/` | Pre-built compliance policy documents |
| Regulations (40+) | `references/` | FATF, MAS, SFC, VARA, OFAC, UN Sanctions |
| Tag Taxonomy | `references/trustin-labels.md` | TrustIn label categories for rule authoring |
| Scripts | `scripts/` | Python screening pipeline |
| Schemas | `schema/` | JSON schemas for rules and reports |

## API

Blockchain data via TrustIn KYA API. **No API key required** — works out of the box with desensitized data.

For full unmasked data: get a free key at [trustin.info](https://trustin.info) and set `TRUSTIN_API_KEY` in `.env`.

## Open Source Ecosystem

| Project | Description |
|---------|-------------|
| **[AMLClaw Skill](https://github.com/amlclaw/amlclaw)** | This repo — AI agent skill, CLI-based, lightweight |
| **[AMLClaw Dashboard](https://github.com/amlclaw/amlclaw.com)** | Full web UI — visual flow graphs, screening history, 24/7 monitoring |

## License

MIT


path: defaults/policies/dubai_vara.md
content: # Dubai VARA — AML/CFT Compliance Policy for Virtual Asset Service Providers

## 1. Jurisdiction & Regulatory Framework

This policy applies to Virtual Asset Service Providers (VASPs) licensed by the Dubai Virtual Assets Regulatory Authority (VARA) under the Dubai Virtual Assets Regulation Law.

**Applicable regulations:**
- **VARA Compliance and Risk Management Rules** — Virtual Asset regulatory framework (Rulebook Sections 3, 4)
- **UAE Federal Decree-Law No. 20 of 2018** — Anti-Money Laundering and Combating the Financing of Terrorism
- **UAE Cabinet Decision No. 10 of 2019** — Implementing regulations for Federal AML Law
- **UAE Executive Office of Anti-Money Laundering and Counter Terrorism Financing (EOCN)** — National coordination
- **FATF 40 Recommendations** (2023 update) — International AML/CFT standards
- **FATF VA/VASP Guidance** (2021) — Virtual asset-specific guidance
- **FATF Recommendation 16** — Travel Rule for wire transfers / VA transfers
- **OFAC SDN List** — US Office of Foreign Assets Control Specially Designated Nationals
- **UN Consolidated Sanctions List** — United Nations Security Council sanctions
- **UAE Local Sanctions List** — Domestic designations under Federal AML Law

## 2. Customer Due Diligence (CDD)

### 2.1 Standard CDD (VARA Rulebook Section 3.1, UAE Federal AML Law)
- Verify identity of all customers before establishing a business relationship using reliable, independent sources
- Identify Ultimate Beneficial Owners (UBOs) with >25% ownership or control
- Assess purpose and intended nature of virtual asset activities
- Continuous due diligence with risk-based approach
- **Transaction threshold**: Full KYC/CDD required for single transactions > AED 3,500 (~USD 950) per rule `UAE-VARA-CDD-HIGH-001`

### 2.2 Enhanced Due Diligence (EDD) (VARA Rulebook Section 3.1)
EDD is required when:
- Customer from high-risk jurisdiction per FATF or UAE National Risk Assessment
- Transaction involves PEPs, their family members, or close associates
- Transactions above AED 55,000 (~USD 15,000) without clear economic rationale
- Complex or unusual transaction patterns
- Blockchain analytics reveal Sanctions/Terrorism exposure at Hop 4-5 — per rule `UAE-VARA-DEP-HIGH-001`
- Any exposure (>0%) to Obfuscation (Mixers, Privacy Tokens) — per rule `UAE-VARA-DEP-HIGH-002` (zero-tolerance, VARA prohibition)
- Cybercrime/Gambling/High-Risk exposure >10% AND >USD 100 — per rule `UAE-VARA-DEP-HIGH-003`
- Target address self-tagged as Cybercrime or Obfuscation — per rules `UAE-VARA-DEP-SELF-HIGH-001`, `UAE-VARA-WDR-SELF-HIGH-001`

EDD procedures include:
- MLRO approval for relationship continuation
- Additional source of funds / source of wealth documentation
- Increased frequency and depth of transaction monitoring
- Detailed rationale documentation for proceeding

## 3. Blockchain-Specific Risk Indicators

Risk categories based on TrustIn KYA label taxonomy, calibrated for VARA requirements:

| Risk Tier | Primary Categories | VARA-Specific Notes |
|-----------|-------------------|-------------------|
| **Severe** | Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, Other Financial Crimes | Zero tolerance. Immediate freeze and FIU report. |
| **High** | Obfuscation | **VARA explicitly prohibits anonymity-enhanced crypto** — any exposure (>0%) triggers Reject (`UAE-VARA-DEP-HIGH-002`) |
| **High** | Cybercrime, Gambling, High-Risk Entities | Threshold-based: >10% exposure AND >USD 100 |
| **Medium** | Other Entities (select) | Black/Grey Industry, MEV Bots/Arbitrage, Spam |
| **Low / Whitelist** | Exchanges & DeFi, Other Entities | CEX, TradFi — whitelist stop rule (`UAE-VARA-WHL-001`) |

**Key VARA distinction**: Dubai applies **zero-tolerance for Obfuscation** (Mixers, Privacy Wallets, Privacy Tokens). VARA explicitly prohibits anonymity-enhanced crypto assets. Any exposure >0% triggers deposit rejection. Additionally, VARA has a **lower CDD threshold** (AED 3,500 / ~USD 950) compared to Singapore and Hong Kong.

## 4. Screening Procedures by Scenario

### 4.1 Deposit Screening
**Inflow analysis** (where did the funds come from?):
- **Hop 1 (direct)**: Sanctions/Terrorism/Illicit → **Freeze** (`UAE-VARA-DEP-SEVERE-001`)
- **Hop 2-3 (near)**: Sanctions/Terrorism/Illicit → **Freeze** (`UAE-VARA-DEP-SEVERE-002`)
- **Hop 4-5 (far)**: Sanctions/Terrorism/Illicit → **EDD** (`UAE-VARA-DEP-HIGH-001`)
- **Zero-tolerance**: Any Obfuscation exposure >0% → **Reject** (`UAE-VARA-DEP-HIGH-002`)
- **Threshold**: Cybercrime/Gambling/High-Risk >10% AND >USD 100 → **EDD** (`UAE-VARA-DEP-HIGH-003`)

**Outflow history** (where has this address previously sent funds?):
- **Hop 1 (direct)**: Funded Sanctions/Terrorism → **Freeze** (`UAE-VARA-DEP-OUT-SEVERE-001`)
- **Hop 2-3 (indirect)**: Funded Sanctions/Terrorism → **EDD** (`UAE-VARA-DEP-OUT-HIGH-001`)

**Self-tag** (is the address itself flagged?):
- Sanctions/Terrorism/Illicit tag → **Freeze** (`UAE-VARA-DEP-SELF-SEVERE-001`)
- Cybercrime/Obfuscation tag → **EDD** (`UAE-VARA-DEP-SELF-HIGH-001`)

### 4.2 Withdrawal Screening
**Outflow analysis** (where are the funds going?):
- **Hop 1 (direct)**: Sanctions/Terrorism destination → **Freeze** (`UAE-VARA-WDR-SEVERE-001`)
- **Hop 2-3 (near)**: Sanctions/Terrorism destination → **Freeze** (`UAE-VARA-WDR-SEVERE-002`)
- **Hop 4-5 (far)**: Sanctions/Terrorism destination → **EDD** (`UAE-VARA-WDR-HIGH-001`)
- **Threshold**: Cybercrime/Obfuscation/Gambling >10% AND >USD 100 → **EDD** (`UAE-VARA-WDR-HIGH-002`)

**Self-tag gate** (is the withdrawing address flagged?):
- Sanctions/Terrorism/Illicit → **Freeze** (`UAE-VARA-WDR-SELF-SEVERE-001`)
- Cybercrime/Obfuscation → **EDD** (`UAE-VARA-WDR-SELF-HIGH-001`)

### 4.3 Onboarding Screening
- Run deposit self-tag and inflow checks against submitted customer addresses
- Severe → reject onboarding, file SAR with FIU
- High → proceed only with EDD and MLRO approval
- Low/Medium → approve with standard monitoring

## 5. Risk Rating Matrix

| Risk Level | Action | Operational Response |
|------------|--------|---------------------|
| **Severe** | Freeze | Immediate asset freeze. Escalate to MLRO. File SAR with UAE FIU within 30 calendar days. No tipping off. |
| **High** | EDD / Reject | Enhanced due diligence or reject (for prohibited categories). Compliance Officer review within 48 hours. |
| **Medium** | Review / Flag | Compliance analyst review within 24 hours. Document rationale. Increase monitoring frequency. |
| **Low** | Allow | Standard processing. Routine monitoring. |

## 6. Suspicious Activity Reporting (SAR)

- **Reporting authority**: UAE Financial Intelligence Unit (FIU)
- **Filing method**: Via **goAML** electronic portal
- **Filing deadline**: Within **30 calendar days** of forming suspicion (UAE Federal AML Law)
- **Tipping off prohibition**: Criminal offence — strictly prohibited to disclose SAR filing to the subject
- **Threshold**: Any transaction where there is reasonable ground to suspect ML/TF, regardless of amount
- **Record keeping**: Maintain copies of all SARs and supporting documentation for minimum 5 years (8 years for high-risk)
- **VARA notification**: Material compliance breaches must be reported to VARA within 5 business days

## 7. Record Keeping Requirements

Per UAE Federal AML Law and VARA Rulebook:
- **CDD records**: Minimum **5 years** after termination of business relationship (**8 years** for high-risk customers)
- **Transaction records**: Minimum **5 years** from date of transaction
- **Screening reports**: Retain all graph data, risk paths, and screening decisions for 5 years
- **SAR records**: Maintain filing records and supporting evidence for 5 years (8 years for high-risk)
- **Ruleset versioning**: Archive all rule configuration changes with timestamps for audit trail
- **VARA compliance records**: Quarterly metrics submissions retained for 5 years

## 8. Travel Rule Compliance (FATF Recommendation 16, UAE Federal AML Law)

Per rule `UAE-VARA-TX-001`:
- **Threshold**: VA transfers > AED 3,500 (~USD 950) trigger Travel Rule and mandatory CDD
- **Required originator information**: Name, account number (wallet address), Emirates ID / passport number, physical address
- **Required beneficiary information**: Name, account number (wallet address)
- **Counterparty VASP verification**: Verify receiving institution is VARA-licensed or equivalent foreign-regulated
- **Cross-border transfers**: Additional originator/beneficiary information required for all cross-border VA transfers above threshold
- **Unhosted wallet transfers**: Require proof of ownership and enhanced CDD

## 9. Sanctions Screening Requirements

### 9.1 Lists to Screen Against
- **OFAC SDN List** — Specially Designated Nationals and Blocked Persons
- **UN Consolidated Sanctions List** — UN Security Council consolidated list
- **FATF High-Risk Jurisdictions** — Countries under increased monitoring or call for action
- **UAE Local Sanctions List** — Domestic designations under Federal AML Law and EOCN directives
- **UAE Targeted Financial Sanctions (TFS)** — Terrorism and proliferation financing designations
- **Arab League sanctions** — Regional sanctions where applicable

### 9.2 Screening Procedures
- Screen all customers and counterparties at onboarding and ongoing
- Re-screen full portfolio within **24 hours** of any sanctions list update (OFAC, UN, UAE local)
- Blockchain address screening via TrustIn KYA API for entity-level sanctions tags
- Name screening with fuzzy matching (minimum 85% match threshold)
- UAE-specific: Screen against EOCN domestic terrorist designation lists

## 10. Ongoing Monitoring

### 10.1 Transaction Monitoring
- **Real-time**: All deposits and withdrawals screened before settlement
- **Structuring detection**: Daily cumulative alerts > USD 950 to prevent AED 3,500 threshold evasion (`UAE-VARA-TX-002`)
- **Periodic re-screening**: Semi-annual full portfolio re-screening for all customers
- **Event-driven**: Immediate re-screening on sanctions list updates or risk escalation
- **VARA reporting**: Quarterly compliance metrics submission

### 10.2 Risk Re-Assessment
- Semi-annual portfolio re-screening for all customers
- Quarterly for high-risk customers
- Addresses may acquire new risk labels over time — ongoing CDD must account for evolving threat intelligence
- Update CDD records when material changes are identified

## 11. Escalation Procedures

1. **Automated flag** → Compliance analyst review within **24 hours**
2. **EDD trigger** → Compliance Officer review within **48 hours**
3. **Freeze trigger** → Immediate MLRO escalation, asset freeze enforced, SAR filed via goAML within 30 calendar days
4. **VARA notification** → Report material compliance breaches to VARA within **5 business days**
5. **Annual review** → Board-level AML/CFT effectiveness review
6. **Regulatory audit** → Maintain readiness for VARA on-site inspections

## 12. Rule-to-Regulation Traceability

| Rule ID | Regulation Reference |
|---------|---------------------|
| UAE-VARA-DEP-SEVERE-001 | UAE Federal AML Law & VARA Rulebook Section 3.1 & OFAC SDN |
| UAE-VARA-DEP-SEVERE-002 | UAE EOCN & VARA Compliance Guidelines 2.1 |
| UAE-VARA-DEP-HIGH-001 | UAE EOCN & Pollution Decay Principle |
| UAE-VARA-DEP-HIGH-002 | VARA Prohibited Activities (Anonymity-Enhanced Crypto) |
| UAE-VARA-DEP-HIGH-003 | TrustIn UAE VARA Guide 2.3 |
| UAE-VARA-DEP-OUT-SEVERE-001 | UAE Federal AML Law & OFAC Indirect Benefits Prohibition |
| UAE-VARA-DEP-OUT-HIGH-001 | UAE Federal AML Law & OFAC Indirect Benefits |
| UAE-VARA-DEP-SELF-SEVERE-001 | UAE Federal AML Law & VARA Rulebook Section 3.1 & FATF Rec 10 |
| UAE-VARA-DEP-SELF-HIGH-001 | VARA Rulebook Section 3.1 (EDD/Ongoing CDD) |
| UAE-VARA-WHL-001 | TrustIn UAE VARA Guide Section 2.1 |
| UAE-VARA-WDR-SEVERE-001 | UAE Federal AML Law & VARA Rulebook Section 4 (STR) |
| UAE-VARA-WDR-SEVERE-002 | UAE Federal AML Law & VARA Rulebook Section 4 (Hop 2-3) |
| UAE-VARA-WDR-HIGH-001 | UAE EOCN & Pollution Decay Principle |
| UAE-VARA-WDR-HIGH-002 | VARA Rulebook Section 3.1 (EDD on Outflow) |
| UAE-VARA-WDR-SELF-SEVERE-001 | UAE Federal AML Law & VARA Rulebook Section 4 (Ongoing CDD) |
| UAE-VARA-WDR-SELF-HIGH-001 | VARA Rulebook Section 3.1 (Ongoing CDD) |
| UAE-VARA-TX-001 | UAE Federal AML Threshold (AED 3,500) |
| UAE-VARA-CDD-HIGH-001 | UAE Federal AML Threshold & VARA CDD Requirements |
| UAE-VARA-TX-002 | TrustIn UAE VARA Guide 3 (Structuring) |


path: defaults/policies/hong_kong_sfc.md
content: # Hong Kong SFC — AML/CFT Compliance Policy for Virtual Asset Service Providers

## 1. Jurisdiction & Regulatory Framework

This policy applies to Virtual Asset Service Providers (VASPs) and Licensed Virtual Asset Trading Platforms (VATPs) operating under the Hong Kong Securities and Futures Commission (SFC) regulatory framework.

**Applicable regulations:**
- **Anti-Money Laundering and Counter-Terrorist Financing Ordinance (AMLO)** — Cap. 615
- **SFC AML/CFT Guidelines** — Guidelines for Licensed Corporations and SFC-Licensed VATPs
- **SFC AML Guideline Sections 4.1.9, 5.10, 12.7, 12.11, 12.14, 12.15.2** — Key provisions for VA screening
- **FATF 40 Recommendations** (2023 update) — International AML/CFT standards
- **FATF VA/VASP Guidance** (2021) — Virtual asset-specific guidance
- **FATF Recommendation 16** — Travel Rule for wire transfers / VA transfers
- **OFAC SDN List** — US Office of Foreign Assets Control Specially Designated Nationals
- **UN Consolidated Sanctions List** — United Nations Security Council sanctions

## 2. Customer Due Diligence (CDD)

### 2.1 Standard CDD (AMLO Schedule 2, SFC AML Guideline 4.1)
- Verify identity of all customers before establishing business relationships
- CDD required for occasional transactions ≥ HKD 8,000 (~USD 1,025)
- Identify and verify beneficial owners (>25% ownership threshold)
- Understand nature and purpose of business relationship
- Ongoing monitoring of transactions and updating of customer information
- **Unhosted wallet threshold**: Full KYC/CDD verification for single transactions > USD 1,000 (~HKD 7,800) per rule `HK-SFC-CDD-HIGH-001`

### 2.2 Enhanced Due Diligence (EDD) (SFC AML Guideline 12.15.2)
EDD is required when:
- Higher ML/TF risk identified through institutional risk assessment
- Customer is a PEP or associated with a PEP
- Transactions linked to FATF high-risk or grey-listed jurisdictions
- Complex or unusually large transactions with no apparent economic purpose
- Blockchain analytics show Sanctions/Terrorism exposure at Hop 4-5 — per rule `HK-SFC-DEP-HIGH-001`
- Any exposure (>0%) to Cybercrime or Obfuscation — per rule `HK-SFC-DEP-HIGH-002` (zero-tolerance)
- Gambling/High-Risk Entities exposure >30% AND >USD 1,000 — per rule `HK-SFC-DEP-HIGH-003`
- Target address self-tagged as Cybercrime or Obfuscation — per rules `HK-SFC-DEP-SELF-HIGH-001`, `HK-SFC-WDR-SELF-HIGH-001`

EDD procedures include:
- Senior management approval for relationship continuation
- Additional source of funds / source of wealth documentation
- Increased frequency and depth of transaction monitoring
- Detailed record keeping of risk assessment rationale

## 3. Blockchain-Specific Risk Indicators

Risk categories based on TrustIn KYA label taxonomy, calibrated for SFC requirements:

| Risk Tier | Primary Categories | SFC-Specific Notes |
|-----------|-------------------|-------------------|
| **Severe** | Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, Other Financial Crimes | Zero tolerance. Immediate freeze and JFIU report. |
| **High** | Cybercrime, Obfuscation | **SFC mandates zero-tolerance** for Mixers/Darknet — any exposure (>0%) triggers Reject (`HK-SFC-DEP-HIGH-002`) |
| **High** | Gambling, High-Risk Entities | Threshold-based: >30% exposure AND >USD 1,000 |
| **Medium** | Other Entities (select) | Black/Grey Industry, MEV Bots/Arbitrage, Spam |
| **Low / Whitelist** | Exchanges & DeFi, Other Entities | CEX, TradFi — whitelist stop rule (`HK-SFC-WHL-001`) |

**Key SFC distinction**: Hong Kong applies **zero-tolerance for Cybercrime and Obfuscation** (Mixers, Privacy Wallets, Privacy Tokens). Any exposure >0% triggers rejection, regardless of amount or hop distance. This is stricter than Singapore's threshold-based approach.

## 4. Screening Procedures by Scenario

### 4.1 Deposit Screening
**Inflow analysis** (where did the funds come from?):
- **Hop 1 (direct)**: Sanctions/Terrorism/Illicit → **Freeze** (`HK-SFC-DEP-SEVERE-001`)
- **Hop 2-3 (near)**: Sanctions/Terrorism/Illicit → **Freeze** (`HK-SFC-DEP-SEVERE-002`)
- **Hop 4-5 (far)**: Sanctions/Terrorism/Illicit → **EDD** (`HK-SFC-DEP-HIGH-001`)
- **Zero-tolerance**: Any Cybercrime/Obfuscation exposure >0% → **Reject** (`HK-SFC-DEP-HIGH-002`)
- **Threshold**: Gambling/High-Risk >30% AND >USD 1,000 → **EDD** (`HK-SFC-DEP-HIGH-003`)

**Outflow history** (where has this address previously sent funds?):
- **Hop 1 (direct)**: Funded Sanctions/Terrorism → **Freeze** (`HK-SFC-DEP-OUT-SEVERE-001`)
- **Hop 2-3 (indirect)**: Funded Sanctions/Terrorism → **EDD** (`HK-SFC-DEP-OUT-HIGH-001`)

**Self-tag** (is the address itself flagged?):
- Sanctions/Terrorism/Illicit tag → **Freeze** (`HK-SFC-DEP-SELF-SEVERE-001`)
- Cybercrime/Obfuscation tag → **EDD** (`HK-SFC-DEP-SELF-HIGH-001`)

### 4.2 Withdrawal Screening
**Outflow analysis** (where are the funds going?):
- **Hop 1 (direct)**: Sanctions/Terrorism destination → **Freeze** (`HK-SFC-WDR-SEVERE-001`)
- **Hop 2-3 (near)**: Sanctions/Terrorism destination → **Freeze** (`HK-SFC-WDR-SEVERE-002`)
- **Threshold**: Cybercrime/Obfuscation/Gambling >10% AND >USD 100 → **EDD** (`HK-SFC-WDR-HIGH-001`)

**Self-tag gate** (is the withdrawing address flagged?):
- Sanctions/Terrorism/Illicit → **Freeze** (`HK-SFC-WDR-SELF-SEVERE-001`)
- Cybercrime/Obfuscation → **EDD** (`HK-SFC-WDR-SELF-HIGH-001`)

### 4.3 Onboarding Screening
- Run deposit self-tag and inflow checks against submitted customer addresses
- Severe → reject onboarding, file STR with JFIU
- High → proceed only with EDD and senior management approval
- Low/Medium → approve with standard monitoring tier

## 5. Risk Rating Matrix

| Risk Level | Action | Operational Response |
|------------|--------|---------------------|
| **Severe** | Freeze | Immediate asset freeze. Escalate to MLRO. File STR with JFIU as soon as reasonably practicable. No tipping off. |
| **High** | EDD / Reject | Enhanced due diligence or reject (for zero-tolerance categories). Compliance Officer review within 48 hours. |
| **Medium** | Review / Flag | Compliance team review within 24 hours. Document rationale. Increase monitoring frequency. |
| **Low** | Allow | Standard processing. Routine monitoring. |

## 6. Suspicious Transaction Reporting (STR)

- **Reporting authority**: Joint Financial Intelligence Unit (JFIU), jointly operated by Hong Kong Police Force and Customs & Excise Department
- **Filing deadline**: As soon as **reasonably practicable** after forming suspicion (AMLO Section 25A)
- **Filing method**: Via JFIU electronic submission portal
- **Tipping off prohibition**: Criminal offence under AMLO Section 25A(4) — strictly prohibited
- **Predicate offences**: Dealing with property known or believed to represent proceeds of an indictable offence (OSCO Section 25) or terrorist property (UNATMO Section 14)
- **Record keeping**: Maintain copies of all STRs and supporting documentation for minimum 6 years
- **Defence STR**: Filing provides a statutory defence against ML/TF charges for the reporting institution

## 7. Record Keeping Requirements

Per AMLO Schedule 2 and SFC AML Guidelines:
- **CDD records**: Minimum **6 years** after termination of business relationship
- **Transaction records**: Minimum **6 years** from date of transaction
- **Screening reports**: Retain all graph data, risk paths, and screening decisions for 6 years
- **STR records**: Maintain filing records and supporting evidence for 6 years
- **Ruleset versioning**: Archive all rule configuration changes with timestamps for audit trail
- **Unhosted wallet assessments**: Retain proof of ownership documentation for 6 years

## 8. Travel Rule Compliance (FATF Recommendation 16, SFC AML Guideline 12.11 & 12.14)

Per rule `HK-SFC-TX-001`:
- **Threshold**: VA transfers > USD 1,000 (~HKD 7,800) trigger Travel Rule and unhosted wallet proof requirements
- **Required originator information**: Name, account number (wallet address), unique transaction reference
- **Required beneficiary information**: Name, account number (wallet address)
- **Counterparty VASP verification**: Verify receiving institution is SFC-licensed or equivalent foreign-regulated
- **Unhosted wallet transfers**: Require proof of ownership (signed message or micro-transaction verification) per SFC Guideline 12.14
- **Threshold for CDD**: Single transaction > USD 1,000 triggers full KYC verification (`HK-SFC-CDD-HIGH-001`)

## 9. Sanctions Screening Requirements

### 9.1 Lists to Screen Against
- **OFAC SDN List** — Specially Designated Nationals and Blocked Persons
- **UN Consolidated Sanctions List** — UN Security Council consolidated list
- **FATF High-Risk Jurisdictions** — Countries under increased monitoring or call for action
- **Hong Kong Designated Lists** — Under United Nations Sanctions Ordinance (Cap. 537) and United Nations (Anti-Terrorism Measures) Ordinance (Cap. 575)
- **PRC sanctions lists** — Where applicable to HK-regulated entities

### 9.2 Screening Procedures
- Screen all customers and counterparties at onboarding and ongoing
- Re-screen full portfolio within **24 hours** of any sanctions list update
- Blockchain address screening via TrustIn KYA API for entity-level sanctions tags
- Name screening with fuzzy matching (minimum 85% match threshold)
- Cross-reference wallet clusters against known sanctioned entity addresses

## 10. Ongoing Monitoring

### 10.1 Transaction Monitoring
- **Real-time**: All deposits and withdrawals screened before processing
- **Structuring detection**: Daily cumulative alerts > USD 10,000 to prevent HKD 8,000 Travel Rule evasion (`HK-SFC-TX-002`)
- **Periodic re-screening**: Quarterly for high-risk customers, annually for standard
- **Event-driven**: Immediate re-screening on sanctions list updates or customer behaviour changes

### 10.2 Risk Re-Assessment
- Quarterly risk reassessment for high-risk customers
- Annual risk reassessment for standard customers
- Addresses may acquire new risk labels over time — ongoing CDD must account for evolving threat intelligence
- Update CDD records when material changes are identified

## 11. Escalation Procedures

1. **Automated flag** → Compliance team review within **24 hours**
2. **EDD trigger** → Compliance Officer review within **48 hours**
3. **Freeze trigger** → Immediate escalation to MLRO, asset freeze enforced, STR filed with JFIU as soon as reasonably practicable
4. **Regulatory reporting** → Quarterly compliance report to SFC, annual AML return
5. **Board reporting** → Quarterly AML/CFT effectiveness report to senior management

## 12. Rule-to-Regulation Traceability

| Rule ID | Regulation Reference |
|---------|---------------------|
| HK-SFC-DEP-SEVERE-001 | SFC AML Guideline 4.1.9 & 12.7 & OFAC SDN Direct Contact |
| HK-SFC-DEP-SEVERE-002 | SFC AML Guideline 4.1.9 & 12.7 |
| HK-SFC-DEP-HIGH-001 | SFC AML Guideline 12.15.2 & Pollution Decay Principle |
| HK-SFC-DEP-HIGH-002 | SFC AML Guideline 12.15.2 (Zero-tolerance Cybercrime/Obfuscation) |
| HK-SFC-DEP-HIGH-003 | TrustIn HK VATP Guide Section 2.1 |
| HK-SFC-DEP-OUT-SEVERE-001 | SFC AML Guideline 4.1.9 & OFAC Indirect Benefits Prohibition |
| HK-SFC-DEP-OUT-HIGH-001 | SFC AML Guideline 12.15.2 & OFAC Indirect Benefits |
| HK-SFC-DEP-SELF-SEVERE-001 | SFC AML Guideline 4.1.9 & FATF Recommendation 10 |
| HK-SFC-DEP-SELF-HIGH-001 | SFC AML Guideline 12.15.2 (CDD/Ongoing CDD) |
| HK-SFC-WHL-001 | TrustIn HK VATP Guide Section 2.1 |
| HK-SFC-WDR-SEVERE-001 | SFC AML Guideline 4.1.9 & 12.7 (Outflow Hop 1) |
| HK-SFC-WDR-SEVERE-002 | SFC AML Guideline 4.1.9 & 12.7 (Outflow Hop 2-3) |
| HK-SFC-WDR-HIGH-001 | SFC AML Guideline 12.15.2 (Outflow EDD) |
| HK-SFC-WDR-SELF-SEVERE-001 | SFC AML Guideline 4.1.9 & 12.7 (Ongoing CDD) |
| HK-SFC-WDR-SELF-HIGH-001 | SFC AML Guideline 12.15.2 (Ongoing CDD) |
| HK-SFC-TX-001 | SFC AML Guideline 12.11 & 12.14 (Travel Rule) |
| HK-SFC-CDD-HIGH-001 | SFC AML Guideline 12.11 (CDD for unhosted wallets) |
| HK-SFC-TX-002 | SFC AML Guideline 5.10 (Structuring) |


path: defaults/policies/singapore_mas.md
content: # Singapore MAS — AML/CFT Compliance Policy for Digital Payment Token Services

## 1. Jurisdiction & Regulatory Framework

This policy applies to Digital Payment Token (DPT) service providers licensed under the Payment Services Act 2019 (PS Act) in Singapore, regulated by the Monetary Authority of Singapore (MAS).

**Applicable regulations:**
- **MAS Notice PSN02** — Prevention of Money Laundering and Countering the Financing of Terrorism for DPT Services
- **MAS Notice PSN08** — Technology Risk Management
- **FATF 40 Recommendations** (2023 update) — International AML/CFT standards
- **FATF VA/VASP Guidance** (2021) — Virtual asset-specific guidance
- **FATF Recommendation 16** — Travel Rule for wire transfers / VA transfers
- **OFAC SDN List** — US Office of Foreign Assets Control Specially Designated Nationals
- **UN Consolidated Sanctions List** — United Nations Security Council sanctions
- **FATF High-Risk Jurisdictions** — Countries with strategic AML/CFT deficiencies

## 2. Customer Due Diligence (CDD)

### 2.1 Standard CDD (MAS Notice PSN02 Section 6)
- Verify identity of all customers before establishing a business relationship
- Obtain beneficial ownership information for legal entities (>25% ownership threshold)
- Understand the purpose and intended nature of the business relationship
- Perform ongoing due diligence including transaction monitoring
- **Occasional transaction threshold**: Full KYC/CDD required for single transactions > SGD 4,700 (~USD 3,500) per rule `SG-DPT-TX-002`

### 2.2 Enhanced Due Diligence (EDD) (MAS Notice PSN02 Section 6)
EDD is required when:
- Customer or counterparty is from a FATF grey/black-listed jurisdiction
- Transaction involves a Politically Exposed Person (PEP) or their associates
- Unusual or complex transaction patterns detected without apparent economic purpose
- Blockchain analytics reveal connections to high-risk entities (Cybercrime, Obfuscation, Gambling, High-Risk Entities) — per rules `SG-DPT-DEP-HIGH-002`, `SG-DPT-WDR-HIGH-002`
- Far-distance (Hop 4-5) exposure to Sanctions or Terrorism Financing — per rules `SG-DPT-DEP-HIGH-001`, `SG-DPT-WDR-HIGH-001`
- Target address self-tagged as Cybercrime or Obfuscation — per rules `SG-DPT-DEP-SELF-HIGH-001`, `SG-DPT-WDR-SELF-HIGH-001`

EDD procedures include:
- Senior management approval for relationship continuation
- Additional source of funds / source of wealth documentation
- Increased frequency of transaction monitoring
- More detailed record keeping of rationale for proceeding

## 3. Blockchain-Specific Risk Indicators

Risk categories are based on TrustIn KYA label taxonomy:

| Risk Tier | Primary Categories | Examples |
|-----------|-------------------|----------|
| **Severe** | Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, Other Financial Crimes | Sanctioned Entity, Terrorist Organization, Law Enforcement Freeze, Human Trafficking, Suspected Money Laundering |
| **High** | Cybercrime, Obfuscation, Gambling, High-Risk Entities | Hacker/Thief, Ransomware, Phishing, Ponzi, Pig Butchering, Mixers, Privacy Wallet, Unlicensed Gambling, Sanctioned CEX |
| **Medium** | Other Entities (select) | Black/Grey Industry, MEV Bots/Arbitrage, Spam |
| **Low / Whitelist** | Exchanges & DeFi, Other Entities | CEX, TradFi, DeFi Protocol, Stablecoin, Mining Pools |

**Whitelist stop rule** (`SG-DPT-WHL-001`): Graph traversal stops at known compliant CEX or TradFi institutions to prevent false positives from deep-chain analysis.

## 4. Screening Procedures by Scenario

### 4.1 Deposit Screening
**Inflow analysis** (where did the funds come from?):
- **Hop 1 (direct)**: Sanctions/Terrorism/Illicit → **Freeze** (`SG-DPT-DEP-SEVERE-001`)
- **Hop 2-3 (near)**: Sanctions/Terrorism/Illicit → **Freeze** (`SG-DPT-DEP-SEVERE-002`)
- **Hop 4-5 (far)**: Sanctions/Terrorism/Illicit → **EDD** (`SG-DPT-DEP-HIGH-001`)
- **Threshold**: Cybercrime/Obfuscation/Gambling/High-Risk >10% AND >USD 50 → **EDD** (`SG-DPT-DEP-HIGH-002`)
- **Threshold**: Grey Industry/Spam >30% AND >USD 1,000 → **Review** (`SG-DPT-DEP-MED-001`)

**Outflow history** (where has this address previously sent funds?):
- **Hop 1 (direct)**: Funded Sanctions/Terrorism → **Freeze** (`SG-DPT-DEP-OUT-SEVERE-001`)
- **Hop 2-3 (indirect)**: Funded Sanctions/Terrorism → **EDD** (`SG-DPT-DEP-OUT-HIGH-001`)

**Self-tag** (is the address itself flagged?):
- Sanctions/Terrorism/Illicit tag → **Freeze** (`SG-DPT-DEP-SELF-SEVERE-001`)
- Cybercrime/Obfuscation tag → **EDD** (`SG-DPT-DEP-SELF-HIGH-001`)

### 4.2 Withdrawal Screening
**Outflow analysis** (where are the funds going?):
- **Hop 1 (direct)**: Sanctions/Terrorism destination → **Freeze** (`SG-DPT-WDR-SEVERE-001`)
- **Hop 2-3 (near)**: Sanctions/Terrorism destination → **Freeze** (`SG-DPT-WDR-SEVERE-002`)
- **Hop 4-5 (far)**: Sanctions/Terrorism destination → **EDD** (`SG-DPT-WDR-HIGH-001`)
- **Threshold**: Cybercrime/Obfuscation/Gambling >10% AND >USD 50 → **EDD** (`SG-DPT-WDR-HIGH-002`)

**Self-tag gate** (is the withdrawing address flagged?):
- Sanctions/Terrorism/Illicit → **Freeze** (`SG-DPT-WDR-SELF-SEVERE-001`)
- Cybercrime/Obfuscation → **EDD** (`SG-DPT-WDR-SELF-HIGH-001`)

### 4.3 Onboarding Screening
- Run deposit self-tag and inflow checks against the customer's submitted addresses
- Severe → reject onboarding, file STR
- High → proceed only with EDD and senior management approval
- Low/Medium → approve with standard monitoring

## 5. Risk Rating Matrix

| Risk Level | Action | Operational Response |
|------------|--------|---------------------|
| **Severe** | Freeze | Immediate asset freeze. Escalate to MLRO. File STR with STRO within 15 business days. No tipping off. |
| **High** | EDD | Enhanced due diligence. Senior compliance officer review within 48 hours. Obtain additional SOF/SOW documentation. |
| **Medium** | Review / Flag | Compliance officer review within 24 hours. Document rationale. Increased monitoring frequency. |
| **Low** | Allow | Standard processing. Routine monitoring. |

## 6. Suspicious Transaction Reporting (STR)

- **Reporting authority**: Suspicious Transaction Reporting Office (STRO), Commercial Affairs Department, Singapore Police Force
- **Filing deadline**: Within **15 business days** of forming suspicion (MAS Notice PSN02 Section 8)
- **Filing method**: Via STRO Online Notices and Reporting (SONAR) platform
- **Tipping off prohibition**: Strictly prohibited to disclose STR filing to the subject or any third party
- **Record keeping**: Maintain copies of all STRs and supporting documentation for minimum 5 years
- **Threshold for mandatory reporting**: Any transaction where there is reasonable ground to suspect ML/TF, regardless of amount

## 7. Record Keeping Requirements

Per MAS Notice PSN02:
- **CDD records**: Minimum **5 years** after termination of business relationship
- **Transaction records**: Minimum **5 years** from date of transaction
- **Screening reports**: Retain all graph data, risk paths, and screening decisions for 5 years
- **STR records**: Maintain filing records and supporting evidence for 5 years
- **Ruleset versioning**: Archive all rule configuration changes with timestamps for audit trail

## 8. Travel Rule Compliance (FATF Recommendation 16)

Per rule `SG-DPT-TX-001`:
- **Threshold**: Single VA transfer > USD 1,000 (~SGD 1,350) triggers Travel Rule obligations
- **Required originator information**: Name, account number (wallet address), physical address / national ID / date of birth
- **Required beneficiary information**: Name, account number (wallet address)
- **Counterparty VASP verification**: Verify the receiving institution is licensed/registered
- **Unhosted wallet transfers**: Require proof of ownership and enhanced CDD for transfers above threshold

## 9. Sanctions Screening Requirements

### 9.1 Lists to Screen Against
- **OFAC SDN List** — Specially Designated Nationals and Blocked Persons
- **OFAC Sectoral Sanctions** — Sectoral Sanctions Identifications List
- **UN Consolidated Sanctions List** — UN Security Council consolidated list
- **FATF High-Risk Jurisdictions** — Countries under increased monitoring or call for action
- **MAS Targeted Financial Sanctions** — Domestic designations under Terrorism (Suppression of Financing) Act and UN Act

### 9.2 Screening Procedures
- Screen all customers and counterparties at onboarding
- Re-screen full portfolio within **24 hours** of any sanctions list update
- Blockchain address screening via TrustIn KYA API for entity-level sanctions tags
- Fuzzy name matching for customer identity vs. sanctions lists (minimum 85% match threshold)

## 10. Ongoing Monitoring

### 10.1 Transaction Monitoring
- **Real-time**: All deposits and withdrawals screened before processing
- **Structuring detection**: Daily cumulative deposit alerts > USD 3,000 (`SG-DPT-TX-003`)
- **Periodic re-screening**: Monthly full portfolio re-screening for ongoing risk changes
- **Event-driven**: Immediate re-screening on sanctions list updates or material risk profile changes

### 10.2 Risk Re-Assessment
- Annual review of all customer risk ratings
- Quarterly review for high-risk customers
- Address risk labels change over time — an address clean at onboarding may be flagged later
- Update CDD records when material changes are identified

## 11. Escalation Procedures

1. **Automated flag** → Compliance officer review within **24 hours**
2. **EDD trigger** → Senior compliance officer review within **48 hours**
3. **Freeze trigger** → Immediate escalation to Money Laundering Reporting Officer (MLRO), asset freeze enforced, STR filed with STRO within 15 business days
4. **Regulatory reporting** → Annual compliance report to MAS
5. **Board reporting** → Quarterly AML/CFT effectiveness report to senior management

## 12. Rule-to-Regulation Traceability

| Rule ID | Regulation Reference |
|---------|---------------------|
| SG-DPT-DEP-SEVERE-001 | MAS Notice PSN02 Section 6 & OFAC SDN Direct Contact |
| SG-DPT-DEP-SEVERE-002 | MAS Notice PSN02 & TrustIn SG DPT Guide Section 1.A |
| SG-DPT-DEP-HIGH-001 | MAS Notice PSN02 & Pollution Decay Principle (OFAC) |
| SG-DPT-DEP-HIGH-002 | TrustIn KYA Pro SG DPT Guide Section 1.B & 2.2 |
| SG-DPT-DEP-MED-001 | TrustIn KYA Pro SG DPT Guide Section 1.C & 2.2 |
| SG-DPT-DEP-OUT-SEVERE-001 | MAS Notice PSN02 & OFAC Indirect Benefits Prohibition |
| SG-DPT-DEP-OUT-HIGH-001 | MAS Notice PSN02 & OFAC Indirect Benefits Prohibition |
| SG-DPT-DEP-SELF-SEVERE-001 | MAS Notice PSN02 Section 6 & FATF Recommendation 10 |
| SG-DPT-DEP-SELF-HIGH-001 | MAS Notice PSN02 Section 6 (CDD/Ongoing CDD) |
| SG-DPT-WHL-001 | TrustIn KYA Pro SG DPT Guide Section 2.1 |
| SG-DPT-WDR-SEVERE-001 | MAS Notice PSN02 Section 8 (STR) & FATF Recommendation 20 |
| SG-DPT-WDR-SEVERE-002 | MAS Notice PSN02 Section 8 & TrustIn SG DPT Guide |
| SG-DPT-WDR-HIGH-001 | MAS Notice PSN02 & Pollution Decay Principle |
| SG-DPT-WDR-HIGH-002 | MAS Notice PSN02 Section 6 (EDD) & TrustIn SG DPT Guide |
| SG-DPT-WDR-SELF-SEVERE-001 | MAS Notice PSN02 Section 6 & 8 (Ongoing CDD + STR) |
| SG-DPT-WDR-SELF-HIGH-001 | MAS Notice PSN02 Section 6 (Ongoing CDD) |
| SG-DPT-TX-001 | TrustIn KYA Pro SG DPT Guide Section 2.3 (Travel Rule) |
| SG-DPT-TX-002 | TrustIn KYA Pro SG DPT Guide Section 2.3 (CDD Threshold) |
| SG-DPT-TX-003 | TrustIn KYA Pro SG DPT Guide Section 2.3 (Structuring) |


path: defaults/rulesets/dubai_vara.json
content: [
  {
    "rule_id": "UAE-VARA-DEP-SEVERE-001",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Inflow Direct Interaction — Sanctions/Terrorism (Hop 1)",
    "description": "Freeze if direct inflow (Hop 1) from Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Direct interaction with sanctioned entities is Critical-level per OFAC and UAE EOCN guidance.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "UAE Federal AML Law & VARA Rulebook Section 3.1 & OFAC SDN Direct Contact = Critical"
  },
  {
    "rule_id": "UAE-VARA-DEP-SEVERE-002",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Inflow Near-Distance — Sanctions/Terrorism (Hop 2-3)",
    "description": "Freeze if near-distance inflow (Hop 2-3) from Sanctions, Terrorism, or Frozen entities. VARA mandates zero tolerance for sanctioned fund sources within traceable distance.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "UAE EOCN & VARA Compliance Guidelines 2.1"
  },
  {
    "rule_id": "UAE-VARA-DEP-HIGH-001",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 4,
    "max_hops": 5,
    "name": "Inflow Far-Distance — Sanctions/Terrorism (Hop 4-5)",
    "description": "Trigger EDD if far-distance inflow (Hop 4-5) from Sanctions, Terrorism, or Frozen entities. Pollution decay reduces severity but sanctions exposure still requires enhanced investigation.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "UAE EOCN & Pollution Decay Principle"
  },
  {
    "rule_id": "UAE-VARA-DEP-HIGH-002",
    "category": "Deposit",
    "direction": "inflow",
    "name": "Inflow Exposure — Obfuscation (Zero-Tolerance)",
    "description": "Reject deposits with any exposure (>0%) to Obfuscation (Mixers, Privacy Tokens). VARA explicitly prohibits anonymity-enhanced crypto assets.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Obfuscation"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 0,
        "unit": "%"
      }
    ],
    "risk_level": "High",
    "action": "Reject",
    "reference": "VARA Prohibited Activities (Anonymity-Enhanced Crypto)"
  },
  {
    "rule_id": "UAE-VARA-DEP-HIGH-003",
    "category": "Deposit",
    "direction": "inflow",
    "name": "Inflow Exposure — Cybercrime/Gambling/High-Risk (Threshold)",
    "description": "Trigger EDD if inflow exposure to Cybercrime, Gambling, or High-Risk Entities exceeds 10% AND risk amount > 100 USD.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Gambling", "High-Risk Entities"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 10,
        "unit": "%"
      },
      {
        "parameter": "path.risk_amount_usd",
        "operator": ">",
        "value": 100,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "TrustIn UAE VARA Guide 2.3"
  },
  {
    "rule_id": "UAE-VARA-DEP-OUT-SEVERE-001",
    "category": "Deposit",
    "direction": "outflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Outflow History — Target Directly Funded Sanctions/Terrorism (Hop 1)",
    "description": "Freeze if the target address has directly sent funds (Hop 1 outflow) to Sanctions, Terrorism, or Frozen entities. Direct outflow to sanctioned entities indicates intentional interaction.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "UAE Federal AML Law & OFAC Prohibition on Providing Indirect Benefits"
  },
  {
    "rule_id": "UAE-VARA-DEP-OUT-HIGH-001",
    "category": "Deposit",
    "direction": "outflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Outflow History — Target Indirectly Funded Sanctions/Terrorism (Hop 2-3)",
    "description": "Trigger EDD if the target address has indirectly funded (Hop 2-3 outflow) Sanctions or Terrorism entities through intermediaries.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "UAE Federal AML Law & OFAC Indirect Benefits Prohibition"
  },
  {
    "rule_id": "UAE-VARA-DEP-SELF-SEVERE-001",
    "category": "Deposit",
    "name": "Target Self-Tag — Sanctions/Freeze/Illicit",
    "description": "Freeze if the target address itself is tagged as Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Applies to both onboarding and deposit.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Public Freezing Action", "Illicit Markets", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "UAE Federal AML Law & VARA Rulebook Section 3.1 (CDD) & FATF Recommendation 10"
  },
  {
    "rule_id": "UAE-VARA-DEP-SELF-HIGH-001",
    "category": "Deposit",
    "name": "Target Self-Tag — Cybercrime/Obfuscation",
    "description": "Trigger EDD if the target address itself is tagged as Cybercrime or Obfuscation. Addresses may acquire new risk labels after onboarding due to evolving threat intelligence.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "VARA Rulebook Section 3.1 (EDD/Ongoing CDD)"
  },
  {
    "rule_id": "UAE-VARA-WHL-001",
    "category": "Deposit",
    "name": "CEX & TradFi Whitelist",
    "description": "Stop penetrating graph paths if a compliant Centralized Exchange or TradFi institution is encountered.",
    "conditions": [
      {
        "parameter": "path.node.tags.secondary_category",
        "operator": "IN",
        "value": ["CEX", "TradFi"]
      }
    ],
    "risk_level": "Low",
    "action": "Whitelist",
    "reference": "TrustIn UAE VARA Guide Section 2.1"
  },
  {
    "rule_id": "UAE-VARA-WDR-SEVERE-001",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Outflow Direct Interaction — Sanctions/Terrorism Destination (Hop 1)",
    "description": "Freeze if direct outflow (Hop 1) reaches Sanctions, Terrorism, or Frozen destination.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "UAE Federal AML Law & VARA Rulebook Section 4 (STR)"
  },
  {
    "rule_id": "UAE-VARA-WDR-SEVERE-002",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Outflow Near-Distance — Sanctions/Terrorism Destination (Hop 2-3)",
    "description": "Freeze if near-distance outflow (Hop 2-3) reaches Sanctions or Terrorism destination.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "UAE Federal AML Law & VARA Rulebook Section 4 (Outflow Hop 2-3)"
  },
  {
    "rule_id": "UAE-VARA-WDR-HIGH-001",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 4,
    "max_hops": 5,
    "name": "Outflow Far-Distance — Sanctions/Terrorism Destination (Hop 4-5)",
    "description": "Trigger EDD if far-distance outflow (Hop 4-5) reaches Sanctions or Terrorism destination. Pollution decay applies but sanctions obligations require enhanced investigation.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "UAE EOCN & Pollution Decay Principle"
  },
  {
    "rule_id": "UAE-VARA-WDR-HIGH-002",
    "category": "Withdrawal",
    "direction": "outflow",
    "name": "Outflow Exposure — Cybercrime/Obfuscation/Gambling Destination (Threshold)",
    "description": "Trigger EDD if outflow reaches Cybercrime, Obfuscation, Gambling, or High-Risk destination with exposure > 10% AND amount > 100 USD.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation", "Gambling", "High-Risk Entities"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 10,
        "unit": "%"
      },
      {
        "parameter": "path.risk_amount_usd",
        "operator": ">",
        "value": 100,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "VARA Rulebook Section 3.1 (EDD on Outflow)"
  },
  {
    "rule_id": "UAE-VARA-WDR-SELF-SEVERE-001",
    "category": "Withdrawal",
    "name": "Withdrawal Gate — Target Self-Tagged (Sanctions/Freeze/Illicit)",
    "description": "Freeze withdrawal if the target address itself is tagged as Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Public Freezing Action", "Illicit Markets", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "UAE Federal AML Law & VARA Rulebook Section 4 (Ongoing CDD)"
  },
  {
    "rule_id": "UAE-VARA-WDR-SELF-HIGH-001",
    "category": "Withdrawal",
    "name": "Withdrawal Gate — Target Self-Tagged (Cybercrime/Obfuscation)",
    "description": "Trigger EDD on withdrawal if the target address itself is tagged as Cybercrime or Obfuscation.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "VARA Rulebook Section 3.1 (Ongoing CDD)"
  },
  {
    "rule_id": "UAE-VARA-TX-001",
    "category": "Withdrawal",
    "name": "VARA Travel Rule & CDD Trigger",
    "description": "Trigger Travel Rule and mandatory CDD for transactions > 950 USD (approx AED 3500).",
    "conditions": [
      {
        "parameter": "path.amount",
        "operator": ">",
        "value": 950,
        "unit": "USD"
      }
    ],
    "risk_level": "Medium",
    "action": "Review",
    "reference": "UAE Federal AML Threshold (AED 3,500)"
  },
  {
    "rule_id": "UAE-VARA-CDD-HIGH-001",
    "category": "CDD",
    "name": "Single Transaction KYC Trigger (>950 USD)",
    "description": "Trigger full KYC/CDD verification if a single transaction exceeds 950 USD (~AED 3500) per UAE threshold.",
    "conditions": [
      {
        "parameter": "path.amount",
        "operator": ">",
        "value": 950,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "UAE Federal AML Threshold (AED 3,500) & VARA CDD Requirements"
  },
  {
    "rule_id": "UAE-VARA-TX-002",
    "category": "Ongoing Monitoring",
    "name": "VARA Structuring Alert",
    "description": "Trigger review if daily cumulative volume > 950 USD to detect smurfing.",
    "conditions": [
      {
        "parameter": "target.daily_deposit_usd",
        "operator": ">",
        "value": 950,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "Review",
    "reference": "TrustIn UAE VARA Guide 3"
  }
]


path: defaults/rulesets/hong_kong_sfc.json
content: [
  {
    "rule_id": "HK-SFC-DEP-SEVERE-001",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Inflow Direct Interaction — Sanctions/Terrorism (Hop 1)",
    "description": "Freeze if direct inflow (Hop 1) from Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Direct contact with sanctioned entities is Critical-level per OFAC guidance.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "SFC AML Guideline 4.1.9 & 12.7 & OFAC SDN Direct Contact = Critical"
  },
  {
    "rule_id": "HK-SFC-DEP-SEVERE-002",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Inflow Near-Distance — Sanctions/Terrorism (Hop 2-3)",
    "description": "Freeze if near-distance inflow (Hop 2-3) from Sanctions, Terrorism, or Frozen entities. Layered funds from sanctioned sources within 3 hops still represent direct taint.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "SFC AML Guideline 4.1.9 & 12.7"
  },
  {
    "rule_id": "HK-SFC-DEP-HIGH-001",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 4,
    "max_hops": 5,
    "name": "Inflow Far-Distance — Sanctions/Terrorism (Hop 4-5)",
    "description": "Trigger EDD if far-distance inflow (Hop 4-5) from Sanctions, Terrorism, or Frozen entities. SFC requires 5-hop inflow penetration; far-distance exposure warrants enhanced investigation but reduced action severity.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "SFC AML Guideline 12.15.2 & Pollution Decay Principle"
  },
  {
    "rule_id": "HK-SFC-DEP-HIGH-002",
    "category": "Deposit",
    "direction": "inflow",
    "name": "Inflow Exposure — Cybercrime/Obfuscation (Zero-Tolerance)",
    "description": "Reject deposits with any exposure (>0%) to Cybercrime or Obfuscation (Mixers, Darknet). SFC mandates zero-tolerance for these categories regardless of hop distance.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 0,
        "unit": "%"
      }
    ],
    "risk_level": "High",
    "action": "Reject",
    "reference": "SFC AML Guideline 12.15.2"
  },
  {
    "rule_id": "HK-SFC-DEP-HIGH-003",
    "category": "Deposit",
    "direction": "inflow",
    "name": "Inflow Exposure — Gambling/High-Risk Entities (Threshold)",
    "description": "Trigger EDD if inflow exposure to Gambling or High-Risk Entities exceeds 30% AND risk amount > 1000 USD.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Gambling", "High-Risk Entities"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 30,
        "unit": "%"
      },
      {
        "parameter": "path.risk_amount_usd",
        "operator": ">",
        "value": 1000,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "TrustIn HK VATP Guide Section 2.1"
  },
  {
    "rule_id": "HK-SFC-DEP-OUT-SEVERE-001",
    "category": "Deposit",
    "direction": "outflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Outflow History — Target Directly Funded Sanctions/Terrorism (Hop 1)",
    "description": "Freeze if the target address has directly sent funds (Hop 1 outflow) to Sanctions, Terrorism, or Frozen entities. Direct outflow to sanctioned entities demonstrates intentional interaction — stronger risk signal than passive inflow exposure.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "SFC AML Guideline 4.1.9 & OFAC Prohibition on Providing Indirect Benefits"
  },
  {
    "rule_id": "HK-SFC-DEP-OUT-HIGH-001",
    "category": "Deposit",
    "direction": "outflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Outflow History — Target Indirectly Funded Sanctions/Terrorism (Hop 2-3)",
    "description": "Trigger EDD if the target address has indirectly funded (Hop 2-3 outflow) Sanctions or Terrorism entities through intermediaries.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "SFC AML Guideline 12.15.2 & OFAC Indirect Benefits Prohibition"
  },
  {
    "rule_id": "HK-SFC-DEP-SELF-SEVERE-001",
    "category": "Deposit",
    "name": "Target Self-Tag — Sanctions/Freeze/Illicit",
    "description": "Freeze if the target address itself is tagged as Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Applies to both onboarding and deposit — risk changes over time, an address clean at onboarding may be flagged later.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Public Freezing Action", "Illicit Markets", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "SFC AML Guideline 4.1.9 (CDD/Ongoing CDD) & FATF Recommendation 10"
  },
  {
    "rule_id": "HK-SFC-DEP-SELF-HIGH-001",
    "category": "Deposit",
    "name": "Target Self-Tag — Cybercrime/Obfuscation",
    "description": "Trigger EDD if the target address itself is tagged as Cybercrime or Obfuscation. Applies to both onboarding and deposit — addresses may acquire new risk labels after onboarding due to evolving threat intelligence.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "SFC AML Guideline 12.15.2 (CDD/Ongoing CDD)"
  },
  {
    "rule_id": "HK-SFC-WHL-001",
    "category": "Deposit",
    "name": "CEX & TradFi Whitelist",
    "description": "Stop penetrating graph paths if a compliant Centralized Exchange or TradFi institution is encountered.",
    "conditions": [
      {
        "parameter": "path.node.tags.secondary_category",
        "operator": "IN",
        "value": ["CEX", "TradFi"]
      }
    ],
    "risk_level": "Low",
    "action": "Whitelist",
    "reference": "TrustIn HK VATP Guide Section 2.1"
  },
  {
    "rule_id": "HK-SFC-WDR-SEVERE-001",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Outflow Direct Interaction — Sanctions/Terrorism Destination (Hop 1)",
    "description": "Freeze if direct outflow (Hop 1) reaches Sanctions, Terrorism, or Frozen destination. SFC outflow monitoring focuses on direct and near-distance (2-3 hops) interaction.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "SFC AML Guideline 4.1.9 & 12.7 (Outflow Hop 1)"
  },
  {
    "rule_id": "HK-SFC-WDR-SEVERE-002",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Outflow Near-Distance — Sanctions/Terrorism Destination (Hop 2-3)",
    "description": "Freeze if near-distance outflow (Hop 2-3) reaches Sanctions or Terrorism destination. SFC guidance recommends 2-3 hop outflow monitoring depth for CFT compliance.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "SFC AML Guideline 4.1.9 & 12.7 (Outflow Hop 2-3)"
  },
  {
    "rule_id": "HK-SFC-WDR-HIGH-001",
    "category": "Withdrawal",
    "direction": "outflow",
    "name": "Outflow Exposure — Cybercrime/Obfuscation/Gambling Destination (Threshold)",
    "description": "Trigger EDD if outflow reaches Cybercrime, Obfuscation, Gambling, or High-Risk destination with exposure > 10% AND amount > 100 USD.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation", "Gambling", "High-Risk Entities"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 10,
        "unit": "%"
      },
      {
        "parameter": "path.risk_amount_usd",
        "operator": ">",
        "value": 100,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "SFC AML Guideline 12.15.2 (Outflow EDD)"
  },
  {
    "rule_id": "HK-SFC-WDR-SELF-SEVERE-001",
    "category": "Withdrawal",
    "name": "Withdrawal Gate — Target Self-Tagged (Sanctions/Freeze/Illicit)",
    "description": "Freeze withdrawal if the target address itself is tagged as Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Prevents sanctioned or frozen addresses from moving funds out.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Public Freezing Action", "Illicit Markets", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "SFC AML Guideline 4.1.9 & 12.7 (Ongoing CDD)"
  },
  {
    "rule_id": "HK-SFC-WDR-SELF-HIGH-001",
    "category": "Withdrawal",
    "name": "Withdrawal Gate — Target Self-Tagged (Cybercrime/Obfuscation)",
    "description": "Trigger EDD on withdrawal if the target address itself is tagged as Cybercrime or Obfuscation. High-risk tagged addresses require enhanced investigation before allowing fund movement.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "SFC AML Guideline 12.15.2 (Ongoing CDD)"
  },
  {
    "rule_id": "HK-SFC-TX-001",
    "category": "Withdrawal",
    "name": "Travel Rule / Unhosted Wallet Trigger",
    "description": "Trigger Travel Rule and Unhosted Wallet Proof of Ownership for amounts > 1000 USD (~7800 HKD).",
    "conditions": [
      {
        "parameter": "path.amount",
        "operator": ">",
        "value": 1000,
        "unit": "USD"
      }
    ],
    "risk_level": "Medium",
    "action": "Review",
    "reference": "SFC AML Guideline 12.11 & 12.14"
  },
  {
    "rule_id": "HK-SFC-CDD-HIGH-001",
    "category": "CDD",
    "name": "Single Transaction KYC Trigger (>1000 USD)",
    "description": "Trigger full KYC/CDD verification if a single transaction exceeds 1000 USD (~7800 HKD) per SFC unhosted wallet threshold.",
    "conditions": [
      {
        "parameter": "path.amount",
        "operator": ">",
        "value": 1000,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "SFC AML Guideline 12.11 (CDD for unhosted wallets)"
  },
  {
    "rule_id": "HK-SFC-TX-002",
    "category": "Ongoing Monitoring",
    "name": "Structuring / Anti-Smurfing Alert",
    "description": "Trigger STR review if daily accumulation > 10000 USD to prevent evading the HKD 8000 Travel Rule limit.",
    "conditions": [
      {
        "parameter": "target.daily_deposit_usd",
        "operator": ">",
        "value": 10000,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "Review",
    "reference": "SFC AML Guideline 5.10 (Structuring)"
  }
]


path: defaults/rulesets/singapore_mas.json
content: [
  {
    "rule_id": "SG-DPT-DEP-SEVERE-001",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Inflow Direct Interaction — Sanctions/Terrorism (Hop 1)",
    "description": "Freeze if direct inflow (Hop 1) from Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Direct interaction indicates intentional or negligent exposure per OFAC Critical-level guidance.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "MAS Notice PSN02 Section 6 & OFAC SDN Direct Contact = Critical"
  },
  {
    "rule_id": "SG-DPT-DEP-SEVERE-002",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Inflow Near-Distance — Sanctions/Terrorism (Hop 2-3)",
    "description": "Freeze if near-distance inflow (Hop 2-3) from Sanctions, Terrorism, or Frozen entities. Near-distance exposure still represents significant taint requiring immediate containment.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "MAS Notice PSN02 & TrustIn SG DPT Guide Section 1.A"
  },
  {
    "rule_id": "SG-DPT-DEP-HIGH-001",
    "category": "Deposit",
    "direction": "inflow",
    "min_hops": 4,
    "max_hops": 5,
    "name": "Inflow Far-Distance — Sanctions/Terrorism (Hop 4-5)",
    "description": "Trigger EDD if far-distance inflow (Hop 4-5) from Sanctions, Terrorism, or Frozen entities. Pollution decay principle: risk reduces with distance, but sanctions exposure still requires enhanced investigation.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "MAS Notice PSN02 & Pollution Decay Principle (OFAC Indirect Benefits)"
  },
  {
    "rule_id": "SG-DPT-DEP-HIGH-002",
    "category": "Deposit",
    "direction": "inflow",
    "name": "Inflow Exposure — Cybercrime/Obfuscation/Gambling/High-Risk (Threshold)",
    "description": "Trigger EDD if inflow exposure to Cybercrime, Mixers, Gambling, or High-Risk Entities exceeds 10% AND risk amount > 50 USD.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation", "Gambling", "High-Risk Entities"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 10,
        "unit": "%"
      },
      {
        "parameter": "path.risk_amount_usd",
        "operator": ">",
        "value": 50,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "TrustIn KYA Pro SG DPT Guide Section 1.B & 2.2"
  },
  {
    "rule_id": "SG-DPT-DEP-MED-001",
    "category": "Deposit",
    "direction": "inflow",
    "name": "Inflow Exposure — Grey Industry/Spam (Threshold)",
    "description": "Trigger SOF Review if inflow exposure to Grey Industry or Spam exceeds 30% AND risk amount > 1000 USD.",
    "conditions": [
      {
        "parameter": "path.node.tags.secondary_category",
        "operator": "IN",
        "value": ["Black/Grey Industry", "MEV Bots/Arbitrage", "Spam"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 30,
        "unit": "%"
      },
      {
        "parameter": "path.risk_amount_usd",
        "operator": ">",
        "value": 1000,
        "unit": "USD"
      }
    ],
    "risk_level": "Medium",
    "action": "Review",
    "reference": "TrustIn KYA Pro SG DPT Guide Section 1.C & 2.2"
  },
  {
    "rule_id": "SG-DPT-DEP-OUT-SEVERE-001",
    "category": "Deposit",
    "direction": "outflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Outflow History — Target Directly Funded Sanctions/Terrorism (Hop 1)",
    "description": "Freeze if the target address has directly sent funds (Hop 1 outflow) to Sanctions, Terrorism, or Frozen entities. Direct outflow to sanctioned entities indicates intentional interaction — far more severe than passive inflow exposure.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "MAS Notice PSN02 & OFAC Prohibition on Providing Indirect Benefits"
  },
  {
    "rule_id": "SG-DPT-DEP-OUT-HIGH-001",
    "category": "Deposit",
    "direction": "outflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Outflow History — Target Indirectly Funded Sanctions/Terrorism (Hop 2-3)",
    "description": "Trigger EDD if the target address has indirectly funded (Hop 2-3 outflow) Sanctions or Terrorism entities. Indirect outflow through intermediaries still requires enhanced investigation.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Other Financial Crimes", "Public Freezing Action", "Illicit Markets"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "MAS Notice PSN02 & OFAC Prohibition on Providing Indirect Benefits"
  },
  {
    "rule_id": "SG-DPT-DEP-SELF-SEVERE-001",
    "category": "Deposit",
    "name": "Target Self-Tag — Sanctions/Freeze/Illicit",
    "description": "Freeze if the target address itself is tagged as Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Applies to both onboarding and deposit — risk changes over time, an address clean at onboarding may be flagged later.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Public Freezing Action", "Illicit Markets", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "MAS Notice PSN02 Section 6 (CDD/Ongoing CDD) & FATF Recommendation 10"
  },
  {
    "rule_id": "SG-DPT-DEP-SELF-HIGH-001",
    "category": "Deposit",
    "name": "Target Self-Tag — Cybercrime/Obfuscation",
    "description": "Trigger EDD if the target address itself is tagged as Cybercrime or Obfuscation. Applies to both onboarding and deposit — addresses may acquire new risk labels after onboarding due to evolving threat intelligence.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "MAS Notice PSN02 Section 6 (CDD/Ongoing CDD)"
  },
  {
    "rule_id": "SG-DPT-WHL-001",
    "category": "Deposit",
    "name": "CEX Whitelist Stop Rule",
    "description": "Stop penetrating graph paths if a known CEX or TradFi institution is encountered to prevent false positives.",
    "conditions": [
      {
        "parameter": "path.node.tags.secondary_category",
        "operator": "IN",
        "value": ["CEX", "TradFi"]
      }
    ],
    "risk_level": "Low",
    "action": "Whitelist",
    "reference": "TrustIn KYA Pro SG DPT Guide Section 2.1"
  },
  {
    "rule_id": "SG-DPT-WDR-SEVERE-001",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 1,
    "max_hops": 1,
    "name": "Outflow Direct Interaction — Sanctions/Terrorism Destination (Hop 1)",
    "description": "Freeze if direct outflow (Hop 1) reaches Sanctions, Terrorism, or Frozen destination. Sending funds directly to sanctioned entities is the highest-severity withdrawal risk.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "MAS Notice PSN02 Section 8 (STR) & FATF Recommendation 20"
  },
  {
    "rule_id": "SG-DPT-WDR-SEVERE-002",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 2,
    "max_hops": 3,
    "name": "Outflow Near-Distance — Sanctions/Terrorism Destination (Hop 2-3)",
    "description": "Freeze if near-distance outflow (Hop 2-3) reaches Sanctions or Terrorism destination. Near-distance outflow to sanctioned entities still requires containment per CFT obligations.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "MAS Notice PSN02 Section 8 & TrustIn SG DPT Guide (Outflow 3-5 Hops)"
  },
  {
    "rule_id": "SG-DPT-WDR-HIGH-001",
    "category": "Withdrawal",
    "direction": "outflow",
    "min_hops": 4,
    "max_hops": 5,
    "name": "Outflow Far-Distance — Sanctions/Terrorism Destination (Hop 4-5)",
    "description": "Trigger EDD if far-distance outflow (Hop 4-5) reaches Sanctions or Terrorism destination. Pollution decay applies but sanctions obligations require enhanced investigation.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Illicit Markets", "Public Freezing Action", "Other Financial Crimes"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "MAS Notice PSN02 & Pollution Decay Principle"
  },
  {
    "rule_id": "SG-DPT-WDR-HIGH-002",
    "category": "Withdrawal",
    "direction": "outflow",
    "name": "Outflow Exposure — Cybercrime/Obfuscation/Gambling Destination (Threshold)",
    "description": "Trigger EDD if outflow reaches Cybercrime, Obfuscation, Gambling, or High-Risk destination with exposure > 10% AND amount > 50 USD.",
    "conditions": [
      {
        "parameter": "path.node.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation", "Gambling", "High-Risk Entities"]
      },
      {
        "parameter": "path.risk_percentage",
        "operator": ">",
        "value": 10,
        "unit": "%"
      },
      {
        "parameter": "path.risk_amount_usd",
        "operator": ">",
        "value": 50,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "MAS Notice PSN02 Section 6 (EDD) & TrustIn SG DPT Guide"
  },
  {
    "rule_id": "SG-DPT-WDR-SELF-SEVERE-001",
    "category": "Withdrawal",
    "name": "Withdrawal Gate — Target Self-Tagged (Sanctions/Freeze/Illicit)",
    "description": "Freeze withdrawal if the target address itself is tagged as Sanctions, Terrorism Financing, Public Freezing Action, Illicit Markets, or Other Financial Crimes. Prevents sanctioned or frozen addresses from moving funds out.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Sanctions", "Terrorism Financing", "Public Freezing Action", "Illicit Markets", "Other Financial Crimes"]
      }
    ],
    "risk_level": "Severe",
    "action": "Freeze",
    "reference": "MAS Notice PSN02 Section 6 & 8 (Ongoing CDD + STR)"
  },
  {
    "rule_id": "SG-DPT-WDR-SELF-HIGH-001",
    "category": "Withdrawal",
    "name": "Withdrawal Gate — Target Self-Tagged (Cybercrime/Obfuscation)",
    "description": "Trigger EDD on withdrawal if the target address itself is tagged as Cybercrime or Obfuscation. High-risk tagged addresses require enhanced investigation before allowing fund movement.",
    "conditions": [
      {
        "parameter": "target.tags.primary_category",
        "operator": "IN",
        "value": ["Cybercrime", "Obfuscation"]
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "MAS Notice PSN02 Section 6 (Ongoing CDD)"
  },
  {
    "rule_id": "SG-DPT-TX-001",
    "category": "Withdrawal",
    "name": "Travel Rule Verification",
    "description": "Trigger Travel Rule verification if single transfer > 1000 USD (~ 1350 SGD).",
    "conditions": [
      {
        "parameter": "path.amount",
        "operator": ">",
        "value": 1000,
        "unit": "USD"
      }
    ],
    "risk_level": "Medium",
    "action": "Review",
    "reference": "TrustIn KYA Pro SG DPT Guide Section 2.3"
  },
  {
    "rule_id": "SG-DPT-TX-002",
    "category": "CDD",
    "name": "Occasional Transaction KYC Trigger",
    "description": "Trigger full KYC/CDD if occasional transaction amount > 3500 USD (~ 4700 SGD).",
    "conditions": [
      {
        "parameter": "path.amount",
        "operator": ">",
        "value": 3500,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "EDD",
    "reference": "TrustIn KYA Pro SG DPT Guide Section 2.3"
  },
  {
    "rule_id": "SG-DPT-TX-003",
    "category": "Ongoing Monitoring",
    "name": "Structuring Alert (Daily Volume)",
    "description": "Trigger alert if daily cumulative deposit > 3000 USD (Anti-smurfing).",
    "conditions": [
      {
        "parameter": "target.daily_deposit_usd",
        "operator": ">",
        "value": 3000,
        "unit": "USD"
      }
    ],
    "risk_level": "High",
    "action": "Review",
    "reference": "TrustIn KYA Pro SG DPT Guide Section 2.3"
  }
]


path: prompts/analysis_prompt.md
content: # AML Screening Report Analysis Prompt

When the user requests an Executive Summary or an explanation of a generated Markdown screening report, you MUST use this prompt to guide your analysis.

## System Instructions
You are an Expert Anti-Money Laundering (AML) Compliance Officer. Your task is to review the output report generated by the `aml-address-screening` tool and summarize it clearly for non-technical stakeholders or account managers.

### Guidelines for Analysis:
1. **Report Status Overview**: Immediately state whether the address is considered Safe, requires Review, or should be Blocked. Mention the exact `Risk Score` and `Risk Level`.
2. **Rule Trigger Explanation (CRITICAL)**: If any Custom Policies (`rules.json`) were triggered, you MUST highlight them in bold. Explain *why* they were triggered (e.g. "This address interacting outwards with a sanctioned entity over 5 hops").
3. **Actionable Recommendation**: Do NOT just paste the raw report. Instead, provide a 1-2 sentence instruction on what the operator should do next based on the `Action Required` field (e.g. "Freeze funds immediately and file an STR" or "Proceed with normal onboarding").
4. **Data Nuance**: If the report shows "Fallback" or "API Error", warn the user that the scan was purely local regex/pattern matching and lacks on-chain depth.

---

### Analysis Output Structure Example
**Address**: [Address]
**Direction**: [Inflow/Outflow]
**Final Status**: 🔴 REJECT (Risk Score: 100/100)

**Executive Summary**:
The requested withdrawal path triggered your **CFT Zero-Tolerance Outflow (SG-DPT-CFT-001)** rule. The address has a direct graph link to `Terrorism Financing` and `Sanctions` within the tracked hops.

**Next Steps**:
As per your local compliance policy, you must freeze this outgoing transaction immediately and escalate the case for STR filing.


path: prompts/evaluation_prompt.md
content: # AML Graph Evaluation Prompt

When the user runs `fetch_graph.py`, it retrieves the raw interaction graph from TrustIn and dumps it locally as `raw_graph_<address>_<timestamp>.json`. Your primary objective as an **Expert AML Analyst Agent** is to act as the Rule Engine: you must cross-reference this raw graph data against the user's `rules.json` policies and generate a highly professional Compliance Audit Report in Markdown format.

## Execution Workflow

1. **Read Files**: Look into the user's current working directory's `./graph_data/risk_paths_<address>_<timestamp>.json` and `./rules.json` files. This `risk_paths` file has already been pre-filtered by Python to contain ONLY nodes in layers 1 through 5 that hit a rule, eliminating noise!
2. **Execute Logic Engine**:
   Analyze every rule from `rules.json`.
   Look into the `risk_entities` array in the JSON. Every entry represents a malicious entity found directly between Hop 1 and Hop 5.

   **Scenario Awareness (CRITICAL):**
   - Check the `scenario` field in the JSON. This tells you which business context was used for filtering.
   - Check `summary.categories_applied` to know which rule categories were active.
   - If the scenario is NOT "all", only rules from those categories were evaluated — mention this in the report.
   - Check `summary.paths_direction_filtered` — if > 0, note how many paths were excluded due to direction filtering.

   **Target Self-Tag Evaluation (CRITICAL for all scenarios):**
   - Check `target.tags` — these are the target address's OWN tags (not from path traversal).
   - Check `target.self_matched_rules` — if non-empty, the target address itself triggered rules (e.g., DEP-SELF-*, WDR-SELF-*).
   - Self-tag rules apply to ALL scenarios (Deposit, Withdrawal, etc.): an address tagged as sanctioned/illicit MUST trigger the corresponding action regardless of fund flows.

   **Tag Priority & Hop Distance Rules (CRITICAL):**
   - The JSON explicitly provides the winning `tag` and the `matched_rules` IDs.
   - When extracting data for your report, DO NOT just stop at `primary_category`. You MUST extract and display `secondary_category`, `tertiary_category`, and `quaternary_category` if they exist. Use them to provide deep context (e.g. `Sanctions / Prohibited Entity / Huionepay / huionepay-deposit`).
   - The overall length of a trace branch (`path.hops`) is DIFFERENT from the illicit node's distance (`node.deep`). You MUST cite the exact `deep` integer of the illicit entity. DO NOT label everything as "Hop 5" just because the total path has 5 hops!
   - **Hop-based risk tiering**: Rules now have `min_hops`/`max_hops` fields that determine their severity based on hop distance. For example:
     - Hop 1 (direct interaction) → typically Severe/Freeze (e.g., `DEP-SEVERE-001`)
     - Hop 2-3 (near-distance) → typically Severe/Freeze (e.g., `DEP-SEVERE-002`)
     - Hop 4-5 (far-distance) → typically High/EDD (e.g., `DEP-HIGH-001`)
   - **Direction-aware rules**: Rules have a `direction` field (`inflow`/`outflow`). DEP-OUT-* rules check the target's outflow history (has the address sent money to sanctioned entities?). This is different from standard inflow analysis.
   - When reporting, group findings by direction AND hop distance to show the severity gradient clearly.

   Match conditions rigorously:
   - Does the `tag.primary_category` IN the graph match the values specified in the rule?
   - Is the `deep` integer matching the numeric threshold (e.g. `== 1`, `<= 3`)?
   - For percentage thresholds, use the `inflow_total_amount` and `outflow_total_amount` fields provided in the JSON to calculate the total exposure percentage against the `path.amount`. Provide your math in the evidence.
3. **Draft the Report**: Base your finding strictly on the entries in the `risk_entities` array and `target.self_matched_rules`. If a `Severe` rule triggers in either, upgrade the `Key Risk Indicators` severity overall.

## Expected Output Format

You must output a polished, audit-ready Markdown document to the `./reports/aml_screening_<address>_<timestamp>.md` path using the exact layout below. **Do not hallucinate data**.

```markdown
# AML Address Screening Report
**Generated:** [YYYY-MM-DD] | **Engine:** Graph Discovery cross-referenced by LLM
**Scenario:** [Scenario Name] | **Categories Applied:** [Deposit / Withdrawal / ALL]
---
### Subject Identification
- **Network**: `[chain]`
- **Address**: `[address]`
- **Validation**: Valid Format

### Target Address Self-Risk Assessment
*(Include this section ONLY if `target.self_matched_rules` is non-empty)*

> **ALERT: Target address has [N] self-tag rule(s) triggered!**

| Tag Category | Risk Level | Triggered Rule(s) | Action |
| :- | :-: | :- | :-: |
| [Sanctions / Prohibited Entity / ...] | [Severe] | `[XX-DEP-SELF-SEVERE-001]` | **Freeze** |

*The target address itself carries risk labels (DEP-SELF-* or WDR-SELF-* rules). This is independent of fund flow analysis and applies to all scenarios.*

### Key Risk Indicators (KRI)
- **Risk Score**: **[0-100]** (Base on highest rule triggered, e.g. Severe = 100, High = 85, Med = 50, Low = 20)
- **Risk Level**: [LOW | MEDIUM | HIGH | CRITICAL]
- **Scenario**: `[DEPOSIT/WITHDRAWAL/CDD/MONITORING/ALL]`
- **Trace Direction**: `[INFLOW/OUTFLOW/ALL]`
- **Paths Analyzed**: [X] total, [Y] excluded by direction filter
- **Recommendation**: [e.g. "Freeze, EDD" based on triggered custom rules]

### Custom Policy Enforcement
*Loaded [X] of [Y] total rules (filtered by scenario: [scenario]).*

> **ALERT: [Z] Custom Rule(s) Triggered!** (Or state "PASS" if none were triggered.)

| Rule ID | Risk Category | Alert Name | Required Action |
| :- | :-: | :- | :-: |
| `[SG-DPT-SEVERE-001]` | **[Severe]** | [Name of Rule] | **[Freeze / EDD / Review]** |
*(Add a row for each rule triggered)*

### On-Chain Graph Discovery
Analyzed **[Total number of flow paths found]** distinct fund flow paths.

| Primary Category | Risk Level | Depth (Hops) | Entities Identified |
| :- | :-: | :-: | :- |
| [Sanctions] | [HIGH] | [0] | [5 interaction(s)] |
*(Sort primarily by Depth/Hop distance to the Subject, and then Risk Level)*

### Detailed Risk Evidence (Path Analysis)
For every rule triggered, you MUST output the exact `evidence_path` string provided in the parsed JSON file. Do not invent the path.

**Example Trace (Direct Interaction):**
- **Trigger**: `[SG-DPT-SEVERE-002]`
- **Illicit Source (Priority=1)**: `Sanctions / Prohibited Entity / Huionepay / huionepay-deposit` at Hop 1 *(Taken from `node.deep`)*
- **Flow Evidence**:
  `[Target Address (TGE94...)] --(100 USD)--> [Sanctioned Entity (TCNKo...)]` *(Taken directly from `evidence_path`)*

**Example Trace (Extended Exposure):**
- **Trigger**: `[SG-DPT-SEVERE-001]`
- **Illicit Source (Priority=1)**: `Sanctions / Prohibited Entity / Huionepay / huionepay-deposit` at Hop 5
- **Flow Evidence**:
  `[Sanctioned Entity (TL1NW...)]` --(700 USDT)--> `[Intermediary Wallet (TCQ...)]` --(700 USDT)--> ... --(50 USDT)--> `[Target Address (TGE94...)]`

*(CRITICAL DIRECTIVE: You MUST relentlessly document ALL paths that trigger Severe or High-risk alerts. Do not arbitrarily truncate. If there are dozens of identical paths from the same entity, you may group them (e.g., "5 identical flows from [Entity A]"), but YOU MUST prove every distinct illicit nexus found in the JSON graph. Ensure you use the deep categorical breakdown for the Illicit Source).*

---
*Report Execution Time: [Execution Time from JSON]*
```


path: references/dubai/迪拜机构链上风控合规配置指南.md
content: # 中东加密企业反洗钱（AML）合规优化配置指南

本指南专为阿联酋迪拜（VARA监管）及中东地区（ADGM/SCA监管）的加密企业（特别是OTC大宗交易商）定制，严格依据阿联酋联邦法规及VARA监管框架，结合最新的AML风险标签分类进行了深度细化。

## 1. 基础合规阈值与系统全局设定
在中东地区经营，系统底层参数必须严格锚定法定红线，确保绝对合规：
*   **转账规则（Travel Rule）与 CDD 阈值**：**AED 3,500（约 USD 950）**。所有大于该阈值的交易均需强制执行Travel Rule并进行客户尽职调查（CDD）。
*   **记录留存期限（Record Keeping）**：**8 年**。系统需支持长达8年的数据长期回溯要求。
*   **资金来源追溯（Inflow Depth）**：**5 层（5 Hops）**。需穿透混淆层，有效识别经过多次跳转试图清洗的资金分层（Layering）。
*   **资金去向监控（Outflow Depth）**：**2-3 层**。重点监控直接接收方及次级接收方，防止资金经由跳板流向恐怖融资等高危地址。

---

## 2. 基于 AML 标签的细化风控规则配置
结合反洗钱(AML)风险标签分类指南，建议将风控规则分为以下响应级别：

### 2.1 🔴 严重违规类（风险等级：严重 1）—— 零容忍与直接冻结
对于涉及制裁、恐怖主义融资及严重金融犯罪的标签，系统风险评分须设为 100，实行零容忍，一旦命中立即冻结或拦截。

| 风险标签分类 (一级) | 具体 AML 标签包含 (二级) | 监管依据与处置动作 |
| :--- | :--- | :--- |
| **制裁 (Sanctions)** | 制裁实体 (Sanctioned Entity)<br>制裁管辖区 (Sanctioned Jurisdiction)<br>发出限制的国家/地址 (Prohibited Entity) | **处置**：出入金实时拦截、冻结资金。<br>**依据**：必须筛查 UN Consolidated List 及阿联酋本地恐怖分子名单 (UAE EOCN)。 |
| **恐怖主义融资 (Terrorism Financing)** | 恐怖组织 (Terrorist Organization) | **处置**：直接拦截，立即报告。 |
| **其他金融犯罪 (Other Financial Crimes)** | 涉嫌洗钱 (Suspected Money Laundering) | **处置**：直接拦截并冻结资金。 |
| **执法冻结 (Public Freezing Action)** | 执法机构冻结 (Law Enforcement Freeze/Seizure) | **处置**：零容忍拦截。 |
| **非法市场 (Illicit Markets)**| 人口贩卖 (Human Trafficking)<br>非法服务 (Illegal Services)<br>儿童虐待 (Child Sexual Abuse Material) | **处置**：直接拒绝入金并触发严重警报。 |

### 2.2 🚫 VARA 明令禁止类（风险等级：高风险 2）—— 阻断混淆与隐私资产
VARA 对“匿名增强型加密货币”及匿名性活动的容忍度为0%，相关活动属于严令禁止范畴。

| 风险标签分类 (一级) | 具体 AML 标签包含 (二级) | 监管依据与处置动作 |
| :--- | :--- | :--- |
| **混淆/隐私 (Obfuscation)** | 混币器 (Mixers)<br>隐私钱包 (Privacy Wallet)<br>隐私代币 (Privacy Token)<br>中心化跨链桥服务 (Centralized Bridge)<br>加密货币ATM (Crypto ATM/Kiosk) | **处置**：风险评分 100，直接拒绝入金。<br>**依据**：VARA 禁止接收匿名币及混币器（如 Tornado Cash）资金，视为最高风险。 |

### 2.3 🟠 网络犯罪类（风险等级：高/中风险 2）—— 动态阈值拦截
对于黑客入侵或链上欺诈类资金，需配置双重阈值进行拦截，以排除小额粉尘攻击（Dust Attacks）。

| 风险标签分类 (一级) | 具体 AML 标签包含 (二级) | 监管依据与处置动作 |
| :--- | :--- | :--- |
| **网络犯罪 (Cybercrime)** | 被盗资金 (Hacker/Thief)、勒索软件 (Ransomware)、网络钓鱼 (Phishing)、庞氏骗局 (Ponzi)、杀猪盘 (Pig Butchering)、项目方跑路 (Rug Pull)、蜜罐合约 (Honeypot)、虚假预售 (Fake Presale)、黑/灰产交易 (Black/Grey Industry) | **触发阈值**：Exposure > 10% 且 Amount > USD 100。<br>**处置**：触发 High 级别警报，识别暗网或欺诈资金，由 MLRO 介入。 |

### 2.4 🟡 敏感与高危实体（风险等级：高风险 3 / 低风险 6）—— 触发 EDD 与所有权验证
此类标签活动需触发增强尽职调查（EDD）及严格验证要求。

| 风险标签分类 (一级) | 具体 AML 标签包含 (二级) | 监管依据与处置动作 |
| :--- | :--- | :--- |
| **博彩 (Gambling)** | 无牌照博彩 (Unlicensed Gambling) | **处置**：阿联酋禁赌，触发 EDD，强制询问资金来源 (Source of Wealth)。 |
| **高风险实体 (High-Risk Entities)**| 高风险地区交易所 (CEX in High-Risk Jurisdiction)、被制裁交易所 (Sanctioned CEX)、弱管控交易所 (CEX with Weak AML/CFT Controls)、场外交易平台 (OTC Desk) | **处置**：严禁与高风险管辖区交互，若交互则触发 SEVERE 级别拦截。 |
| **辅助类 (Other Entities) - 非托管钱包**| 自托管钱包 (Self-custody Wallet)、AA钱包 (AA Wallet) | **处置**：标记为 High Risk。提币金额 > USD 950 时，强制要求所有权证明（Satoshi Test）。 |

---

## 3. 动态交易模式与交互规则 (Interaction Rules)
针对 OTC 业务中常见的规避监管行为，需要结合系统规则进行动态聚类监控：

*   **拆分交易监控 (Structuring/Smurfing)**：同一地址（或同一聚类簇）在 **24 小时内** 累计交易金额 > USD 950。即便单笔金额小于 $950，只要累计超过该阈值，系统必须自动合并计算并强制触发 CDD 要求与 Travel Rule 门槛。
*   **高风险 VASP 交互**：识别与高风险辖区（High Risk Jurisdictions，如FATF黑名单国家）交易所地址的交互，予以直接拦截（SEVERE）；同时建议将持牌合规交易所（如 Binance, Kraken）加入白名单以减少误报。

---

## 4. 事后监控与持续审查机制 (Ongoing Monitoring)
为满足 VARA 极高的情报响应要求与持续监控规定，需开启Ongoing Monitoring模块并配置严密的审查流程：

1.  **标签变动实时预警**：对 OTC 高净值客户进行**每日扫描（Daily）**，对零售客户在交易时进行实时扫描并**每周回溯**。若历史交易地址被新增标记为“被盗资金 (Hacker)”或“欺诈 (Scam)”等，系统需立即报警。
2.  **制裁名单时效响应**：当 UN 或阿联酋本地名单（UAE EOCN）更新时，系统必须在 **24 小时内** 完成所有存量地址的回溯扫描。
3.  **可疑交易报告（STR）与响应时效**：一旦由反洗钱报告官（MLRO）确认可疑交易，必须立即通过 **GoAML** 平台向阿联酋金融情报中心（UAE FIU）提交报告。若 FIU 提出进一步信息请求，企业必须在 **48 小时内** 作出回复。

path: references/fatf/FATF-003-Targeted-Update-VA-VASP-2025.md
content: # FATF Targeted Update on Virtual Assets and VASPs - June 2025

**Source**: FATF (fatf-gafi.org)
**Published**: 26 June 2025
**Type**: Implementation Review Report

---

## Overview

The Financial Action Task Force (FATF) released its sixth targeted review of global implementation of AML standards for virtual assets (VAs) and virtual asset service providers (VASPs).

---

## Key Findings

### 1. Overall Compliance Status (Recommendation 15)

| Status | Percentage | Change from 2024 |
|--------|------------|------------------|
| Largely Compliant (LC) | 29% | +4% |
| Partially Compliant (PC) | 49% | - |
| Non-Compliant (NC) | 21% | -4% |
| Fully Compliant | 1 jurisdiction | - |

### 2. Risk Assessment Progress

- **76%** of jurisdictions (124 of 163) have conducted ML/TF risk assessments for VAs/VASPs (up from 71% in 2024)
- Only **40 of 138** assessed jurisdictions adequately met risk assessment requirements

### 3. Regulatory Approaches

| Approach | Percentage | Change from 2024 |
|----------|------------|------------------|
| Determined regulatory approach | 82% | +9% |
| Permit VA/VASP operations | 62% | - |
| Prohibition (full or partial) | 20% | +6% |
| Partial prohibition only | 48% of prohibiting | - |

### 4. VASP Licensing/Registration

- **96 jurisdictions** require VASP licensing/registration
- **76 jurisdictions** have actually licensed/registered VASPs in practice (up from 69 in 2024)
- **37%** of jurisdictions apply licensing requirements to offshore VASPs

---

## Travel Rule Implementation

### Global Progress

| Metric | Status |
|--------|--------|
| Jurisdictions with Travel Rule legislation | 58% |
| Jurisdictions enforcing Travel Rule | 42% |
| VASPs with Travel Rule solutions | 65% (estimated) |

### Key Challenges

1. Lack of interoperable technical solutions
2. Sunrise issue (asymmetric implementation across jurisdictions)
3. Unhosted wallet transactions
4. Cross-border enforcement gaps

---

## Emerging Threats Identified

1. **DeFi Platforms**: Increased use for money laundering
2. **Privacy Coins**: Continued AML/CFT risks
3. **Cross-chain Bridges**: Exploited for obfuscation
4. **NFT Markets**: Emerging ML/TF vulnerabilities
5. **Stablecoins**: Rapid growth requiring enhanced oversight

---

## FATF Recommendations

### For Jurisdictions

1. Complete implementation of R.15 and R.16 (Travel Rule)
2. Enhance supervision and enforcement capabilities
3. Conduct regular risk assessments
4. Strengthen international cooperation

### For VASPs

1. Implement robust AML/CFT programs
2. Deploy Travel Rule compliance solutions
3. Enhance transaction monitoring for VA-specific risks
4. Report suspicious transactions promptly

---

## Materially Important VA Sectors

FATF identified jurisdictions with materially important VA sectors requiring priority attention:

- United States
- United Kingdom
- Singapore
- Hong Kong SAR
- United Arab Emirates
- Japan
- South Korea
- Germany
- Switzerland
- Australia

---

## Next Steps

- FATF will continue monitoring implementation progress
- Updated guidance expected for DeFi and unhosted wallets
- Enhanced focus on Travel Rule enforcement
- Continued mutual evaluation assessments

---

**Reference**: https://www.fatf-gafi.org/en/publications/Fatfrecommendations/targeted-update-virtual-assets-vasps-2025.html


path: references/fatf/FATF-005-Travel-Rule-Best-Practices-2025.md
content: # Best Practices on Travel Rule Supervision

URL Source: https://www.fatf-gafi.org/content/dam/fatf-gafi/recommendations/Best-Practices-Travel-Rule-Supervision.pdf

Region: International
Issuer: FATF
Published: June 2025

---

## Table of Contents

1. Understanding the landscape
   - 1.1. Background
   - 1.2. Implementation of the FATF's Travel Rule
   - 1.3. Overall status of jurisdiction implementation since 2024
2. Evolution and challenges
   - 2.1. The Sunrise issue
   - 2.2. Unhosted Wallets
   - 2.3. Capacity, risk understanding and training
   - 2.4. Travel Rule tools: interoperability challenge and tool deficiencies
3. Good practices
   - 3.1. Pre-implementation phase
   - 3.2. Use of thematic reviews prior to enforcing Travel Rule compliance
   - 3.3. Setting clear regulatory expectations
   - 3.4. Building a risk-based supervisory lifecycle
   - 3.5. Engagement with private sector

---

## 1. Understanding the Landscape

### 1.1. Background

In 2019, the FATF agreed to extend the application of the FATF Standards to Virtual Assets (VAs) and Virtual Asset Service Providers (VASPs). Through amendments to Recommendation 15 (R.15) and its Interpretative Note (R.15/INR.15), this required jurisdictions to:

- **License or register VASPs** to prevent them from being misused by criminals or their associates
- **Require VASPs to implement preventative measures**, such as conducting customer due diligence and monitoring for suspicious activity
- **Mandate an authority to apply risk-based supervision** to VASPs to ensure they meet their obligations

The **Travel Rule** requires VASPs and FIs to obtain, hold, and transmit specific originator and beneficiary information immediately and securely when transferring VAs. This payment transparency underpins effective financial investigations and compliance with targeted financial sanctions.

### 1.2. Implementation of the FATF's Travel Rule

The Travel Rule applies the FATF's payment transparency requirements (FATF Recommendation 16) to the VA context. The Travel Rule requires VASPs and financial institutions to obtain, hold, and transmit specific originator and beneficiary information immediately and securely when transferring VAs.

#### Purpose of the Travel Rule

The Travel Rule is a key AML/CFT measure that enables VASPs and financial institutions to prevent terrorists, money launderers, proliferation financiers and other criminals from accessing wire transfers. Specifically, these requirements ensure that basic originator and beneficiary information is available to:

- **Law enforcement authorities** to detect, investigate and prosecute terrorists or other criminals and trace their assets
- **Financial intelligence units** to analyse suspicious or unusual activity
- **Ordering intermediary and beneficiary VASPs and financial institutions** to identify and report suspicious transactions and to freeze funds and prevent transactions with sanctioned persons or entities

### 1.3. Overall Status of Jurisdiction Implementation Since 2024

**Enactment of Travel Rule Legislation**: In 2025, **85 out of 163** surveyed jurisdictions reported having legislation passed to implement the Travel Rule, compared to just 65 jurisdictions in 2024. An additional 14 jurisdictions reported being in the process of implementing the Travel Rule.

**Regional Overview**: There is an increase in implementation across Moneyval and FATF member jurisdictions, partly due to the passing in the EU of the Markets in Crypto-Assets Regulation (MiCAR) and the revised Transfer of Funds regulation.

Of the 85 jurisdictions that have passed legislation enacting the Travel Rule, approximately half have measures in place to ensure domestic VASPs are only transacting with licensed/registered and/or Travel Rule-compliant counterparts (57%; 49 of 85).

---

## 2. Evolution and Challenges

### 2.1. The Sunrise Issue

In the context of VA regulation, the **'Sunrise Issue'** refers to the uneven adoption of the Travel Rule across jurisdictions, arising from delays and/or inconsistent standards.

Compliance with the Travel Rule requires VASPs to ensure that certain information requirements accompany payment flows. However, given lack of consistent implementation between jurisdictions, it may not always be the case that both VASPs involved in a transaction will be required by their respective national authorities to comply with the Travel Rule.

As of 2025, 99 out of 164 jurisdictions have implemented the Travel Rule or are in the process of doing so, demonstrating substantial improvement over 2024.

### 2.2. Unhosted Wallets

While peer-to-peer (P2P) transfers are not explicitly subject to AML/CFT controls under the FATF, the 2021 Updated Guidance makes clear that jurisdictions and VASPs must nonetheless mitigate the relevant risks where appropriate. VASPs should:

- Collect the required originator and beneficiary information even when conducting a transfer between their customer and an unhosted wallet
- Verify ownership of unhosted wallets
- Implement adequate transaction monitoring measures

### 2.3. Capacity, Risk Understanding and Training

As VASP supervision is relatively nascent globally, it takes time to develop technical expertise and supervisory and enforcement capacity. The highly technical nature of the Travel Rule has made this common shortcoming more acute.

To address this gap:
- Both VASPs and supervisors should ensure continuous training of their staff
- VASPs should explain the objectives of the Travel Rule and the role it plays in detecting potential illicit activity
- Supervisors should be trained on how to clearly articulate obligations and address deficiencies

### 2.4. Travel Rule Tools: Interoperability Challenge and Tool Deficiencies

While the FATF Standards do not require interoperability between Travel Rule compliance tools, a lack of interoperability can present frictions and reduce a VASPs' ability to fully comply with Travel Rule requirements.

In deciding which Travel Rule compliance tool to adopt, VASPs should consider:
- Interoperability with other tools
- Ability to transact with more counterparties in a Travel Rule-compliant manner
- Tool deficiencies that may complicate compliance

---

## 3. Good Practices

### 3.1. Pre-implementation Phase

Some jurisdictions have sought to overcome challenges by gaining a robust understanding of their VASP population, including size, risk, and compliance capabilities, ahead of supervising for compliance with Travel Rule requirements.

Collected information could include:
- The VASP's understanding of Travel Rule obligations
- Trading volumes (incl. exposure to jurisdictions that have not implemented the Travel Rule)
- Travel Rule policies and processes
- Travel Rule compliance tools used

#### Example: Singapore (MAS)

Singapore's MAS:
- Engaged with available Travel Rule Compliance tool providers
- Raised industry's awareness via industry engagement sessions
- Issued additional guidance in March 2021
- Supported industry initiatives for independent evaluation of Travel Rule compliance tool providers

#### Example: United Kingdom (FCA)

The FCA divided the VASP population into three groups: high, medium and low risk, allowing it to initially allocate most supervisory resources to category 1 firms deemed most material.

### 3.2. Use of Thematic Reviews Prior to Enforcing Travel Rule Compliance

Supervisors may use thematic reviews based on supervisory information to understand the degree to which VASPs are prepared to comply with Travel Rule requirements.

#### Example: Gibraltar (GFSC)

In 2024, Gibraltar's GFSC launched a thematic review focused on Travel Rule compliance, examining:
- The average number of Travel Rule compliant transactions
- How many VASPs had chosen and started to implement a Travel Rule solution
- Whether solutions were enabling them to meet all key regulatory expectations
- What obstacles for full Travel Rule implementation had been identified

### 3.3. Setting Clear Regulatory Expectations

Effective guidance should:
- Be based on a clear understanding of the ML/TF risks identified
- Be targeted, practical, up-to-date, and actionable
- Outline supervisory expectations (e.g., good practices, bad practices, high-risk areas)
- Be effectively disseminated to the VASP community

#### Example: Hong Kong China

Hong Kong enhanced its AML/CFT requirements in June 2023 with VA specific guidance including:
- Clarification that VASPs are responsible for ensuring Travel Rule compliance when using Travel Rule solutions
- Details on how to meet Travel Rule obligations in transactions involving unhosted wallets

#### Example: Japan

The Japanese Financial Services Agency (JFSA) publishes annually a list of equivalent jurisdictions. As of April 2025, **28 equivalent jurisdictions** have been identified as compliant with Travel Rule.

### 3.4. Building a Risk-based Supervisory Lifecycle

#### Travel Rule Compliance as a Condition for Registration/Licensing

Authorities may consider making compliance with the Travel Rule a prerequisite for the licensing of VASPs. Approaches include:
- **Live demonstrations** (Bahamas)
- **Regulatory sandboxes** (Kazakhstan)
- **On-site reviews at licensing stage** by specialised teams (Hong Kong, Singapore)

#### Use of Third Parties

Supervisors may use third parties (such as external consultants or auditors) to support their AML/CFT functions, including:
- Requiring VASPs to obtain an independent audit/test of their policies, procedures and controls
- Following-up on the adequacy of undertaken remediation

#### Overcoming Capacity and Training Gaps

- Hong Kong's SFC established a specialised team with supervision and AML/CFT expertise
- Use of blockchain analytics tools for sample testing of transaction data
- Gibraltar's GFSC leverages blockchain analytics tools to assess transaction exposure at entity and jurisdiction levels

#### Remedial Actions and Sanctions

Supervisors should have a sufficient range of sanctions available that can be applied proportionately to breaches of supervisory requirements, from remedial actions to formal enforcement actions.

### 3.5. Engagement with Private Sector

Regular information sharing, education and outreach with and across the private sector to improve understanding of risks, including through:
- Public-private partnerships
- Structured dialogues
- Capacity building efforts

#### Example: Singapore

MAS actively conducted industry engagements which led to industry initiatives, including independent evaluations on Travel Rule Solution Providers against FATF R.16 and technology/cybersecurity requirements.

#### Example: India

India established permanent working groups with VASPs to have periodic meetings and discuss Travel Rule as a priority topic. India's FIU is also guiding the establishment of an industry centre of excellence.

---

## Next Steps

1. The FATF will continue monitoring updates in the VA ecosystem, including the implementation of the Travel Rule by jurisdictions.

2. The FATF will explore potential next steps to promote consistent and timely implementation across all jurisdictions to address the Sunrise Issue.

3. The revised R.16/INR.16 adopted in June 2025 will have implications for the VA sector. FATF will address in upcoming guidance how the new framework will apply to VAs and VASPs.

---

## Key Statistics

| Metric | 2023 | 2024 | 2025 |
|--------|------|------|------|
| Jurisdictions with Travel Rule legislation | 35 | 65 | 85 |
| Jurisdictions in process of implementing | 27 | 15 | 14 |
| No Travel Rule implementation | 28 | 14 | 18 |

---

## Citing Reference

FATF (2025), Best Practices on Travel Rule Supervision, FATF, Paris,
https://www.fatf-gafi.org/content/dam/fatf-gafi/recommendations/Best-Practices-Travel-Rule-Supervision.pdf

(c) 2025 FATF/OECD. All rights reserved.


path: references/hongkong/香港机构链上风控合规配置指南.md
content: 这是一份为您定制的**香港虚拟资产交易反洗钱风控配置指南**，已将反洗钱(AML)风险标签分类深度融合进 TrustIn KYA Pro 规则引擎中，并严格采用 Markdown 格式输出：

# 优化版：香港虚拟资产交易反洗钱风控配置指南

本策略专为受香港证监会（SFC）监管的持牌虚拟资产交易平台（VATP）及 OTC 交易商定制，基于 TrustIn KYA Pro 平台进行配置。本指南严格遵循香港《打击洗钱及恐怖分子资金筹集条例》(AMLO, Cap. 615) 及证监会发布的《打击洗钱及恐怖分子资金筹集指引》(SFC AML Guideline)。

## 1. 监管背景与核心合规义务

*   **适用主体**：持有 SFC 第 1/7 类牌照的交易所、根据 AMLO 申领 VASP 牌照的平台，以及从事 OTC 业务的持牌法团。
*   **关键合规痛点**：资金来源审查 (Source of Funds)、转账规则 (Travel Rule)、制裁筛查 (Sanctions Screening) 及持续监控 (Ongoing Monitoring)。

---

## 2. 结合 AML 风险标签的规则引擎配置 (Rule Engine Configuration)

针对 OTC 及机构业务大额、高频的特点，建议将**反洗钱标签分类**深度嵌入 TrustIn KYA Pro 的策略中。

### 2.1 入金审查 (Inflow Rules) - 识别资金来源与非法活动

SFC AML Guideline 第 4.1.9 及 12.7 段要求对客户进行尽职调查，确立资金来源，并识别匿名性高、混币器或欺诈相关的风险。建议配置如下：

*   **追溯方向 (Trace Direction)**：Inflow (资金来源)。
*   **穿透深度 (Trace Depth)**：**5 Hops (5层)**。洗钱者常利用多层转账清洗资金，5层深度能有效穿透复杂的洗钱剥离链 (Peel Chains)。

**基于风险标签的拦截策略：**

| 风险等级 | 包含的 AML 标签分类 | 建议阈值设定与应对措施 |
| :--- | :--- | :--- |
| **严重 1 (Severe)** | **制裁** (制裁实体/管辖区、限制国家)；**恐怖主义融资** (恐怖组织)；**其他金融犯罪** (涉嫌洗钱)；**执法冻结** (执法机构)；**非法市场** (人口贩卖、非法服务、儿童虐待)。 | **Risk Score > 0 (零容忍)**。一旦发现任何关联，立即冻结，严禁处理受制裁资金。 |
| **高风险 2 (High)** | **网络犯罪** (被盗资金、勒索软件、网络钓鱼、杀猪盘、庞氏骗局、项目方跑路、蜜罐合约、虚假预售)；**混淆/隐私** (混币器、隐私钱包/代币、中心化跨链桥、加密货币ATM)。 | **Risk Score > 0 (零容忍/直接拒绝)**。SFC 明确指出混币器和暗网（勒索/黑客）属高风险，建议直接拒绝入金。 |
| **高风险 3 (High)** | **博彩** (无牌照博彩)；**高风险实体** (高风险地区/被制裁/弱管控交易所、OTC平台、高风险跨链桥)。 | **Risk Score > 30% AND Amount > $1,000**。若此类资金来源占比过高，需执行增强尽职调查 (EDD)，要求客户解释资金来源。 |
| **中风险 2/5/6 (Medium)** | **网络犯罪** (黑/灰产交易)；**辅助类** (MEV机器人/套利、垃圾交易/空投)。 | 结合客户行为综合评估，触发异常时需人工介入核实。 |
| **低风险 3-7 (Low)** | **交易所 & DeFi** (合规 CEX、TradFi、借贷协议、流动性质押等)；**辅助类实体** (稳定币发行、资金托管服务商、矿池、智能合约账户、AA钱包等)。 | **开启白名单 (Whitelist: Enable)**。遇到如 Binance、Kraken 等合规白名单地址将停止穿透，避免误报。 |

### 2.2 出金/转账监控 (Outflow Rules) - Travel Rule 与制裁筛查

*   **追溯方向与深度**：Outflow (资金去向)，穿透深度 **2-3 Hops**。重点监控直接与次级接收方，防范资金流向受制裁实体。
*   **Travel Rule 触发阈值**：**> USD 1,000 (约 HKD 7,800)**。法规要求为 HKD 8,000，设为 1,000 美元可缓冲汇率波动，触发后系统需强制收集 IVMS101 标准信息。
*   **非托管钱包 (Unhosted Wallet)**：设定风险等级为 **High (需额外核实)**。SFC 规定必须对此类转账采取额外措施，如所有权验证 (Proof of Ownership/Satoshi Test)。
*   **制裁筛查 (Sanctions Screening)**：必须覆盖 **Global Lists + HK Lists** (联合国及香港宪报名单)。

### 2.3 交互行为检测 (Interaction Rules) - 识别异常交易模式

针对 SFC AML Guideline 第 5.10 段及附录 B 的要求：

| 规则名称 (Rule Name) | 阈值设置 | 触发等级 | 合规应对措施 |
| :--- | :--- | :--- | :--- |
| **Structuring (拆分交易)** | 单日累计 > USD 10,000 且单笔 < USD 1,000 | 🟠 High | 防范“蚂蚁搬家”规避 Travel Rule，需提交可疑交易报告(STR)。 |
| **Rapid Movement (快进快出)** | 资金入账后 1 小时内全额转出 | 🟡 Medium | 属于 SFC 指出的可疑指标，需人工复核交易目的。 |
| **New/Inactive Wallet** | 目标地址为新创建或长期休眠 | 🟡 Medium | 防止勒索软件攻击或诈骗资金转移。 |

---

## 3. 事后监控配置 (Ongoing Monitoring Configuration)

根据 SFC 要求，需对业务关系和客户资料进行持续监控。在 TrustIn 中针对通过 KYC 的白名单地址开启 **"Ongoing Monitoring"** (7x24 小时监控)。

*   **核心触发机制 (Trigger Events)**：
    *   **Sanctions Hit**：地址被新列入 UN/OFAC 制裁名单（严重 1 标签）时，系统需在 24 小时内报警。
    *   **Risk Profile Change**：客户地址风险评分从 Low 突变为 High/Severe（例如被标记为“被盗资金”或“杀猪盘”）。
    *   **Unexpected Interaction**：客户地址突然与“暗网”或“混币器”产生交互。
*   **监控频率与留存**：高风险客户 (High Risk/PEP) 每日扫描；标准客户每周或实时扫描。系统风险警报和处理记录必须保存至少 **5 年**。

---

## 4. 监控阈值配置汇总表 (Configuration Summary)

| 模块 (Module) | 参数 (Key Parameter) | 设定值 (Value) | 对应 SFC 合规要求 |
| :--- | :--- | :--- | :--- |
| **Inflow** | 穿透深度 (Trace Depth) | **5 Hops** | 识别 Peel Chains / Layering |
| **Inflow** | 混币器容忍度 (Mixer Tolerance) | **0% (Reject)** | 针对匿名性风险 (SFC 12.15.2) |
| **Outflow** | Travel Rule 触发金额 | **> USD 1,000** | 对应 HKD 8,000 门槛 (SFC 12.11) |
| **Outflow** | 非托管钱包 (Unhosted Wallet) | **Enable "Proof of Ownership"** | 针对非托管钱包的额外措施 (SFC 12.14) |
| **Identity** | 制裁名单筛查 | **UN + HK Gazette** | 满足 UNATMO/UNSO 要求 |
| **Interaction** | 大额偶然交易 CDD 门槛 | **> HKD 120,000 (约 $15k)** | 对应偶然交易 CDD 门槛 (SFC 4.1.9) |

---

## 5. 操作流程 (SOP) 建议

1.  **Pre-Trade (交易前)**：OTC 交易员收到客户地址后，输入 TrustIn KYA Pro 扫描。
    *   若命中 **Severe (严重)** 标签，**拒绝交易**并上报合规部（考虑提交 STR）。
    *   若命中 **High (高风险)** 标签（如混币器），要求客户提供有力资金来源证明；否则拒绝。
2.  **During-Trade (交易中)**：提币金额 > USD 1,000 时，系统自动检查 Beneficiary VASP 信息；若目标为非托管钱包，启动 Satoshi Test 等所有权验证流程。
3.  **Post-Trade (交易后)**：将地址加入 TrustIn 的 **Ongoing Monitoring** 列表持续监控。定期（如每月）导出监控报告，作为合规审计底稿，确保有效规避合规风险。

path: references/sanctions/SANC-001-FATF-High-Risk-Jurisdictions.md
content: # FATF High-Risk and Monitored Jurisdictions

**Purpose**: Reference for jurisdiction-based risk assessment and enhanced due diligence requirements
**Key Assumptions**: Updated per FATF Plenary meetings (February, June, October annually)
**Usage Patterns**: Geographic risk scoring; EDD triggers; transaction monitoring rules

---

## Overview

- **Authority**: Financial Action Task Force (FATF)
- **Update Frequency**: Three times per year (following Plenary meetings)
- **Latest Update**: October 2025
- **Source**: https://www.fatf-gafi.org/en/countries/black-and-grey-lists.html

---

## Part 1 - High-Risk Jurisdictions (Black List)

### Definition

Countries with significant strategic deficiencies in their AML/CFT/CPF regimes. FATF calls on all members to apply enhanced due diligence and, in most serious cases, countermeasures.

### Current Black List (October 2025)

| Jurisdiction | Status | Required Actions |
|--------------|--------|------------------|
| **Iran** | Countermeasures | Apply countermeasures proportionate to risks |
| **Democratic People's Republic of Korea (DPRK)** | Countermeasures | Apply countermeasures proportionate to risks |
| **Myanmar** | Enhanced Due Diligence | Apply enhanced due diligence only |

### Countermeasures

For Iran and DPRK, jurisdictions should consider:
- Limiting or prohibiting financial transactions
- Prohibiting establishment of subsidiaries or branches
- Limiting business relationships
- Enhanced reporting requirements
- Requiring increased external audit

### Enhanced Due Diligence

For Myanmar and other high-risk countries:
- Obtain additional information on customer and beneficial owner
- Obtain senior management approval for new relationships
- Conduct enhanced ongoing monitoring
- Consider purpose and reason for transactions

---

## Part 2 - Jurisdictions Under Increased Monitoring (Grey List)

### Definition

Countries actively working with FATF to address strategic deficiencies under agreed timelines. Not subject to countermeasures but require enhanced due diligence.

### October 2025 Changes

**Removed from Grey List:**
- Burkina Faso
- Mozambique
- Nigeria
- South Africa

### Current Grey List (as of October 2025)

| Region | Jurisdictions |
|--------|---------------|
| **Africa** | Democratic Republic of Congo, Mali, Senegal, Tanzania |
| **Asia-Pacific** | Philippines, Vietnam |
| **Europe** | Bulgaria, Croatia |
| **Middle East** | Syria, Yemen |
| **Americas** | Haiti, Jamaica, Venezuela |
| **Other** | Monaco |

*Note: List subject to change. Verify against official FATF publications.*

### Required Actions for Grey List

- Apply enhanced due diligence proportionate to risks
- Monitor transactions with additional scrutiny
- Consider additional information requirements
- Apply risk-based approach in business decisions

---

## Part 3 - Compliance Requirements

### Enhanced Due Diligence Triggers

Transactions involving high-risk or grey-listed jurisdictions require:

| Requirement | Black List | Grey List |
|-------------|------------|-----------|
| Additional customer information | Mandatory | Risk-based |
| Senior management approval | Mandatory | Recommended |
| Enhanced ongoing monitoring | Mandatory | Required |
| Source of funds verification | Mandatory | Risk-based |
| Purpose of transaction documentation | Mandatory | Risk-based |

### Transaction Monitoring

For jurisdictions on either list:
1. Flag transactions for manual review
2. Investigate unusual patterns
3. Document rationale for proceeding
4. Consider STR filing if suspicious

### Record Keeping

- Document all EDD measures taken
- Retain records for regulatory period (typically 5-6 years)
- Be prepared for regulatory inspection

---

## Part 4 - Virtual Asset Considerations

### VA-Specific Risks

| Risk Factor | Consideration |
|-------------|---------------|
| **Sanctions evasion** | VAs used to circumvent financial sanctions |
| **Anonymity** | Privacy coins and mixers obscure origins |
| **Cross-border** | Rapid cross-border movement without intermediaries |
| **DeFi** | Decentralized protocols may lack controls |

### VASP Obligations

- Screen wallet addresses against sanctions lists
- Apply geographic risk scoring to counterparties
- Monitor for patterns indicating sanctions evasion
- Report suspicious activities to authorities

### High-Risk Indicators

- Transactions with known high-risk jurisdiction VASPs
- Wallet addresses associated with sanctioned entities
- Patterns suggesting layering through multiple jurisdictions
- Use of privacy-enhancing technologies

---

## Part 5 - Updates History

### 2025 Changes

| Date | Additions | Removals |
|------|-----------|----------|
| October 2025 | - | Burkina Faso, Mozambique, Nigeria, South Africa |
| June 2025 | TBD | TBD |
| February 2025 | TBD | TBD |

### 2024 Changes

| Date | Additions | Removals |
|------|-----------|----------|
| October 2024 | Algeria, Angola, Cote d'Ivoire, Lebanon | Barbados, Gibraltar, Uganda, UAE |
| June 2024 | Monaco, Venezuela | Senegal (returned later) |

---

## Part 6 - Implementation Guidance

### Risk Scoring

| Jurisdiction Type | Suggested Risk Score |
|-------------------|---------------------|
| Black List (Countermeasures) | Critical / Prohibited |
| Black List (EDD) | Very High |
| Grey List | High |
| FATF Member | Standard |
| Non-FATF, Non-Listed | Elevated |

### System Configuration

1. Maintain updated jurisdiction risk database
2. Configure transaction monitoring rules
3. Set alert thresholds for high-risk countries
4. Automate screening where possible
5. Document override decisions

---

## Referenced Documents

| Document | Description |
|----------|-------------|
| FATF Recommendations | 40 Recommendations framework |
| FATF Methodology | Assessment methodology |
| Mutual Evaluation Reports | Country-specific assessments |
| FATF Guidance on VA/VASPs | Virtual asset specific guidance |

---

## Relevance to TrustIn Reports

- Geographic risk scoring for transaction counterparties
- EDD trigger identification for compliance workflows
- Jurisdiction risk indicators in analysis reports
- Regulatory requirement mapping by jurisdiction


path: references/sanctions/SANC-002-OFAC-Virtual-Currency-Guidance.md
content: # OFAC Virtual Currency Sanctions Compliance Guidance

**Purpose**: U.S. sanctions compliance requirements for virtual currency transactions
**Key Assumptions**: Applies to U.S. persons and entities under OFAC jurisdiction
**Usage Patterns**: Sanctions screening; SDN list checking; compliance program design

---

## Overview

- **Authority**: Office of Foreign Assets Control (OFAC), U.S. Department of the Treasury
- **Legal Basis**: International Emergency Economic Powers Act (IEEPA); Trading with the Enemy Act (TWEA)
- **Applies to**: U.S. persons, entities, and foreign persons engaging with U.S. financial system
- **Source**: https://ofac.treasury.gov/faqs/topic/1626

---

## Part 1 - Definitions

### Virtual Currency

| Term | Definition |
|------|------------|
| **Digital Currency** | Sovereign cryptocurrency, virtual currency (non-fiat), and digital representation of fiat currency |
| **Virtual Currency** | Digital representation of value that functions as medium of exchange, unit of account, or store of value without government backing |
| **Digital Currency Address** | Alphanumeric identifier associated with wallet that can receive transfers |
| **Hosted Wallet Provider** | Business that creates and stores wallets for customers |

### Persons Subject to OFAC

- U.S. citizens and permanent residents (anywhere in world)
- Entities organized under U.S. law
- Persons physically present in the U.S.
- Foreign branches of U.S. entities
- Foreign persons dealing with U.S. origin goods/services

---

## Part 2 - Compliance Obligations

### Core Requirements

All persons subject to OFAC jurisdiction must:

| Obligation | Description |
|------------|-------------|
| **Screen transactions** | Check against SDN List and other sanctions lists |
| **Block property** | Freeze assets of designated persons |
| **Avoid dealings** | Refrain from unauthorized transactions with sanctioned entities |
| **Report blocked property** | Report within 10 business days, then annually |

### Equal Application

OFAC sanctions apply equally regardless of:
- Transaction type (fiat vs. virtual currency)
- Technology used
- Location of parties (if U.S. nexus exists)

### Risk-Based Compliance Programs

Organizations should develop:
- Tailored compliance programs appropriate to business model
- Screening procedures for virtual currency transactions
- Training for staff handling virtual currency
- Escalation procedures for potential matches

---

## Part 3 - SDN List and Digital Currencies

### Digital Currency Addresses on SDN List

OFAC designates specific wallet addresses using structured format:
- Format: "Digital Currency Address - [Currency Code]"
- Example: "Digital Currency Address - XBT" (Bitcoin)
- Example: "Digital Currency Address - ETH" (Ethereum)

### Searching the SDN List

| Method | Description |
|--------|-------------|
| **Sanctions List Search Tool** | Official OFAC search interface |
| **ID # Field** | Use for exact address matches |
| **Downloadable Files** | XML, CSV, PDF formats available |
| **API Access** | For automated screening |

### Designated Entities (Examples)

| Entity/Address Type | Examples |
|---------------------|----------|
| **Ransomware operators** | Addresses used in ransomware attacks |
| **Darknet markets** | Addresses associated with illegal marketplaces |
| **Sanctioned exchanges** | Garantex, Suex, Chatex |
| **State actors** | DPRK-affiliated addresses, Iranian addresses |

---

## Part 4 - Blocking and Reporting

### Blocking Requirements

When virtual currency belonging to SDN is identified:

| Action | Requirement |
|--------|-------------|
| **Deny access** | Prevent all parties from accessing blocked assets |
| **Segregate** | Separate blocked assets from other holdings |
| **Document** | Maintain records of blocking action |
| **Preserve** | Do not transfer, convert, or dispose of assets |

### Reporting Requirements

| Report Type | Deadline | Method |
|-------------|----------|--------|
| **Initial blocking report** | 10 business days | OFAC online portal |
| **Annual report** | By September 30 annually | OFAC online portal |
| **Rejected transaction report** | 10 business days | OFAC online portal |

### Unblocking Process

Customers may request unblocking through:
1. OFAC online application portal
2. Specific license request
3. Demonstrate case of mistaken identity
4. Await delisting of underlying designation

---

## Part 5 - Enforcement

### Recent Enforcement Actions

| Entity | Date | Action | Amount |
|--------|------|--------|--------|
| **Garantex** | August 2025 | Re-designation | N/A (asset freeze) |
| **Grinex** | August 2025 | Designation | N/A (asset freeze) |
| **Tornado Cash** | August 2022 | Designation | $7+ billion processed |
| **Blender.io** | May 2022 | Designation | First mixer sanctioned |

### Penalty Framework

| Violation Type | Civil Penalty | Criminal Penalty |
|----------------|---------------|------------------|
| **Willful violation** | Up to $1M per violation | Up to 20 years imprisonment |
| **Non-willful violation** | Up to $250K per violation | N/A |
| **Corporate violation** | Greater of $250K or twice transaction value | Corporate criminal liability |

### Mitigating Factors

OFAC considers:
- Existence of compliance program
- Voluntary self-disclosure
- Cooperation with investigation
- Remedial measures taken

---

## Part 6 - Specific Sanctions Programs

### Iran

| Prohibition | Scope |
|-------------|-------|
| **Financial transactions** | Nearly all transactions prohibited |
| **Virtual currency** | Included in comprehensive sanctions |
| **Secondary sanctions** | Foreign persons may face sanctions for Iran dealings |

### DPRK (North Korea)

| Prohibition | Scope |
|-------------|-------|
| **All transactions** | Comprehensive embargo |
| **Virtual currency** | Known to use crypto for sanctions evasion |
| **Cyber operations** | State-sponsored hacking linked to crypto theft |

### Russia

| Prohibition | Scope |
|-------------|-------|
| **Financial sector** | Broad restrictions on financial institutions |
| **Oligarchs** | Individual designations with crypto holdings |
| **Specific exchanges** | Garantex and successors designated |

### Ransomware-Related

| Focus | Description |
|-------|-------------|
| **Addresses** | Wallet addresses used in ransomware payments |
| **Operators** | Individuals operating ransomware schemes |
| **Facilitators** | Exchanges and mixers facilitating payments |

---

## Part 7 - Compliance Best Practices

### Screening Implementation

1. **Real-time screening**: Screen transactions before processing
2. **Batch screening**: Regular rescreening of customer base
3. **Address format handling**: Account for different address formats
4. **Fuzzy matching**: Consider variations and aliases

### Transaction Monitoring

| Indicator | Risk Level |
|-----------|------------|
| **Direct SDN address** | Critical - Block immediately |
| **One-hop from SDN** | High - Enhanced review |
| **Mixer/tumbler use** | High - Investigate source |
| **High-risk jurisdiction** | Elevated - Apply EDD |

### Documentation

Maintain records of:
- All screening results
- False positive resolutions
- Blocking actions and reports
- Compliance program updates

---

## Part 8 - Technical Considerations

### Blockchain Analysis

| Capability | Purpose |
|------------|---------|
| **Address clustering** | Identify related addresses |
| **Transaction tracing** | Follow fund flows |
| **Risk scoring** | Assess address risk levels |
| **Pattern detection** | Identify evasion techniques |

### API Integration

OFAC provides:
- Sanctions List Search API
- Downloadable list files (updated daily)
- Structured data formats

### Multi-Chain Considerations

| Chain | OFAC Designations |
|-------|-------------------|
| **Bitcoin (XBT)** | Yes - addresses designated |
| **Ethereum (ETH)** | Yes - addresses and smart contracts |
| **Other chains** | Emerging - TRON, BSC addresses appearing |

---

## Referenced Regulations

| Regulation | Description |
|------------|-------------|
| 31 CFR Part 501 | OFAC administrative procedures |
| 31 CFR Part 560 | Iranian Transactions and Sanctions Regulations |
| 31 CFR Part 510 | North Korea Sanctions Regulations |
| 31 CFR Part 589 | Ukraine-Related Sanctions Regulations |
| EO 13694 | Blocking Property of Certain Persons Engaging in Significant Malicious Cyber-Enabled Activities |

---

## Relevance to TrustIn Reports

- Address screening against OFAC SDN list
- Transaction risk scoring based on sanctions exposure
- Compliance evidence for regulated entity customers
- Cross-reference with on-chain analysis findings


path: references/sanctions/SANC-003-UN-Consolidated-Sanctions.md
content: # UN Consolidated Sanctions List

**Source**: United Nations Security Council
**Type**: Consolidated Sanctions Reference
**Update Frequency**: As resolutions are adopted

---

## Overview

The UN Security Council Consolidated List includes all individuals and entities subject to sanctions measures imposed by the Security Council. This list is the foundation for many national sanctions regimes.

---

## Key Sanctions Regimes Relevant to Virtual Assets

### 1. DPRK (North Korea) Sanctions

**Resolution**: UNSCR 1718 (2006) and subsequent resolutions

**Relevance to Crypto**:
- DPRK-linked actors actively use cryptocurrency for sanctions evasion
- Lazarus Group and related APT actors
- Crypto exchange hacks attributed to DPRK

**Key Designations**:
- Lazarus Group
- Reconnaissance General Bureau (RGB)
- Various front companies and individuals

### 2. Iran Sanctions

**Resolution**: UNSCR 1737 (2006) and subsequent resolutions

**Relevance to Crypto**:
- Iranian entities using crypto to evade financial sanctions
- Mining operations to generate foreign currency
- Cross-border payments via virtual assets

### 3. Terrorism-Related Sanctions

**Resolution**: UNSCR 1267 (1999) - Al-Qaida/ISIL (Da'esh)

**Relevance to Crypto**:
- Terrorist financing via cryptocurrency donations
- Use of privacy coins and mixers
- Cross-border fund transfers

---

## How to Access UN Sanctions Data

### Official Sources

1. **UN Security Council Consolidated List**
   - URL: https://www.un.org/securitycouncil/content/un-sc-consolidated-list
   - Format: XML, PDF
   - Updates: Real-time

2. **Sanctions List Search**
   - URL: https://scsanctions.un.org/search/
   - Interactive search tool

### Data Fields Available

| Field | Description |
|-------|-------------|
| Reference Number | Unique identifier |
| Name | Full name/entity name |
| Aliases | Known aliases |
| Date of Birth | For individuals |
| Nationality | Country of origin |
| Address | Known addresses |
| Passport/ID | Document numbers |
| Listing Date | When added to list |
| Narrative | Reason for listing |

---

## Integration with AML Systems

### Screening Requirements

1. **Customer Screening**
   - Screen all customers against UN list
   - Real-time or batch screening
   - Fuzzy matching for name variations

2. **Transaction Screening**
   - Screen counterparties
   - Screen wallet addresses (where linked to sanctioned entities)
   - Geographic screening

### Best Practices

1. **Data Updates**
   - Subscribe to UN sanctions updates
   - Implement automated list updates
   - Document update procedures

2. **Match Handling**
   - Clear escalation procedures
   - Documentation requirements
   - Regulatory reporting

3. **Record Keeping**
   - Retain screening records
   - Document false positive dispositions
   - Audit trail maintenance

---

## Crypto-Specific Designations

### OFAC Designated Crypto Addresses

Note: While UN does not directly designate crypto addresses, OFAC (US) has designated specific addresses linked to UN-sanctioned entities:

- Lazarus Group wallet addresses
- Tornado Cash smart contracts
- Various mixer services

### Cross-Reference Requirements

For comprehensive sanctions screening in crypto:
1. UN Consolidated List
2. OFAC SDN List (includes crypto addresses)
3. EU Consolidated List
4. National sanctions lists (as applicable)

---

## Regulatory Expectations

### FATF Guidance

- Targeted Financial Sanctions (TFS) must cover VAs/VASPs
- Real-time screening for high-risk transactions
- Ability to freeze assets without delay

### Jurisdictional Requirements

| Jurisdiction | Requirement |
|--------------|-------------|
| Singapore | MAS requires UN + Singapore lists |
| Dubai | VARA requires UN + UAE lists |
| Hong Kong | SFC requires UN + HK lists |

---

## Resources

- **UN SC Consolidated List**: https://www.un.org/securitycouncil/content/un-sc-consolidated-list
- **UN Sanctions App**: https://www.un.org/securitycouncil/content/un-sc-consolidated-list-app
- **FATF TFS Guidance**: https://www.fatf-gafi.org/

---

**Note**: This document provides an overview for compliance reference. Always consult official UN sources for the authoritative and current sanctions list.


path: references/singapore/新加坡DPT持牌机构链上风控合规配置指南.md
content: 这是一份专为持有新加坡 DPT（数字支付代币）牌照 ，特别是从事 OTC（场外交易） 业务的企业设计的 TrustIn KYA Pro 反洗钱（AML）与反恐融资（CFT）配置策略文档。本指南深度融合了 TrustIn 最新的 AML 标签分类体系，严格依据 新加坡金融管理局 (MAS) 的监管要求（包括 2025 年修订的 PSN02 通知）、新加坡警方 (SPF) STRO 发布的红旗指标以及 TSOFA / 联合国法案 制定。
--------------------------------------------------------------------------------
1. 核心风控标签与风险等级映射 
根据 TrustIn 最新的标签分类体系，系统内必须将以下地址标签映射至对应的风险等级，以触发不同的风控动作。
A. 严重风险 (SEVERE) - 零容忍绝对拦截
此类风险涉及 MAS 及新加坡法律的红线，必须立即拦截、冻结并考虑上报：
• 制裁 (Sanctions)：制裁实体 (Sanctioned Entity)、制裁管辖区 (Sanctioned Jurisdiction)、发出限制的国家/地址 (Prohibited Entity Singapore)。
• 恐怖主义融资 (Terrorism Financing)：恐怖组织 (Terrorist Organization)。
• 其他金融犯罪 (Other Financial Crimes) & 执法冻结 (Public Freezing Action)：涉嫌洗钱 (Suspected Money Laundering)、执法机构冻结 (Law Enforcement Freeze/Seizure)。
• 非法市场 (Illicit Markets)：人口贩卖 (Human Trafficking)、非法服务 (Illegal Services)、儿童虐待 (Child Sexual Abuse Material/CSAM)。
B. 高风险 (HIGH) - 拒绝交易或强制 EDD
此类风险高度契合 SG-010 红旗指标中的洗钱上游犯罪及资金混淆手段：
• 网络犯罪 (Cybercrime)：被盗资金 (Hacker/Thief)、勒索软件 (Ransomware)、网络钓鱼 (Phishing)、庞氏骗局 (Ponzi)、杀猪盘 (Pig Butchering)、项目方跑路 (Rug Pull)、蜜罐合约 (Honeypot)、虚假预售 (Fake Presale)。
• 混淆/隐私 (Obfuscation)：混币器 (Mixers)、隐私钱包 (Privacy Wallet)、隐私代币 (Privacy Token)、中心化跨链桥服务 (Centralized Bridge)、加密货币ATM (Crypto ATM)。
• 博彩 (Gambling)：无牌照博彩 (Unlicensed Gambling)。
• 高风险实体 (High-Risk Entities)：高风险地区交易所 (CEX in High-Risk Jurisdiction)、被制裁交易所 (Sanctioned CEX)、弱AML/CFT管控交易所 (CEX with Weak AML/CFT Controls)、场外交易平台 (OTC Desk)、高风险跨链桥服务 (High-Risk Bridges)。
C. 中风险 (MEDIUM) - 触发人工审核/关注
• 网络犯罪：黑/灰产交易 (Black/Grey Industry)。
• 辅助类实体：MEV机器人/套利 (MEV Bots/Arbitrage)、垃圾交易/空投 (Spam)。
D. 低风险 (LOW) - 正常放行与白名单
• 交易所 & 去中心化金融协议 (Exchanges & DeFi)：中心化交易所 (CEX)、传统金融机构 (TradFi)、DeFi 协议、DEX、CDP、衍生品协议、收益创造协议、跨链桥服务 (Bridges)、NFT市场等。
• 辅助类 (Other Entities)：稳定币发行 (Stablecoin)、资金托管服务商 (Custodian)、多签钱包 (Multisig Wallet)、自托管钱包 (Self-custody Wallet) 等。
--------------------------------------------------------------------------------
2. 规则引擎配置与阈值设定 (Rule Engine & Thresholds)
针对 OTC 业务大额、低频、高风险的特点，建议在 TrustIn KYA Pro 中配置以下核心规则：
2.1 资金来源与去向追踪逻辑
• 资金来源审查 (Inflow)：追溯资金上游，穿透深度建议设置为 5 Hops (5层)，以有效防止犯罪分子通过 Peel Chains（剥离链）进行分层 (Layering) 洗钱。
• 资金去向监控 (Outflow)：监控提币目标地址及其下游，穿透深度建议设置为 3-5 Hops，确保识别资金是否流向恐怖组织或受制裁实体。
• 白名单机制 (Whitelist)：必须开启，将低风险的合规 CEX (如 Binance, Coinbase) 热钱包加入白名单，TrustIn 的穿透阻断机制将在遇到白名单时停止，有效降低误报率。
2.2 阈值与逻辑的具体设置
在 Fund 规则中，建议使用逻辑组合来平衡风控与业务体验，避免恶意的“粉尘攻击”(Dusting Attack) 导致误杀：
• 严重风险 (SEVERE) 规则：
    ◦ 触发逻辑：Percentage > 0% OR Direct Interaction（只要包含 0.01% 的受制裁/恐融资金，或有直接交互）。
    ◦ 应对措施：Block (冻结/拦截)。
• 高风险 (HIGH) 规则：
    ◦ 触发逻辑：Percentage > 10% AND Risk Amount > 50 USD。
    ◦ 应对措施：Reject (拒绝交易) 或要求客户提供增强尽职调查 (EDD)。过滤掉 50 USD 以下的资金可防范黑客的微量粉尘脏币。
• 中风险 (MEDIUM) 规则：
    ◦ 触发逻辑：Percentage > 30% AND Risk Amount > 1,000 USD。
    ◦ 应对措施：要求确认资金来源 (Source of Funds) 的合法性。
2.3 交互行为检测 (匹配 MAS 法规门槛)
• 转账规则 (Travel Rule)：单笔转账 **> 1,000USD∗∗(约合S1,350)，触发中风险 (Medium) 警报，系统强制要求填写受益人 VASP 信息。
• CDD 触发阈值：偶然交易金额 **> 3,500USD∗∗(约合S4,700)，触发高风险 (High) 警报，强制执行完整的 KYC/CDD 流程。
• 拆分交易警报 (Structuring Alert)：单日累计入金 > $3,000 USD，触发高风险 (High) 警报，警惕客户通过“蚂蚁搬家”规避 CDD 审查。
--------------------------------------------------------------------------------
3. 事后监控配置 (Ongoing Monitoring)
MAS 要求 DPT 服务商必须进行持续监控。建议在 TrustIn 系统中针对存量客户地址开启以下功能：
1. 每日回溯筛查 (Daily Screening)：
    ◦ 区块链标签具有动态性，需监控存量高净值客户的白名单地址。
    ◦ 触发条件：地址风险评分从 Low (低风险) 突变为 High/Severe (高/严重风险)，或新增与制裁名单 (Sanction List) 的交互。
2. 交易模式监控 (Transaction Pattern Monitoring)：
    ◦ 快进快出 (Rapid Movement)：资金充值后极短时间内全额提走。
    ◦ 拆分 (Structuring)：检测 24 小时内多次低于 S$5,000 的入金行为。
    ◦ 行为不符 (Inconsistent Activity)：交易量突然激增，与客户申报的财务状况不符。
--------------------------------------------------------------------------------
4. 操作流程与合规文档留存 (SOP & Record Keeping)
根据 MAS PSN02 规定，业务人员需严格执行以下操作流程：
1. 交易前 (Pre-Trade)：
    ◦ 将客户钱包地址输入 TrustIn KYA Pro 进行筛查。
    ◦ 导出并存档 PDF 报告；若提币金额超过阈值，必须通过 Travel Rule 协议（如 Sygna, Notabene）发送 IVMS101 标准信息。
2. 警报处理 (Alert Handling)：
    ◦ 触发 HIGH 警报时，必须由合规官 (Compliance Officer) 介入。
    ◦ 执行 EDD 措施，要求客户提供资金来源证明。若客户无法合理解释资金为何涉及高风险标签（如混币器），必须向 STRO 提交 STR (可疑交易报告)。
3. 记录留存 (Record Retention)：
    ◦ 所有 TrustIn 分析报告、客户解释文件、STR 提交记录必须依法保存至少 5 年

path: references/trustin-labels.md
content: 以下是根据来源资料为您整理的 AML（反洗钱）标签分类 Markdown 表格：

| 一级分类「英文」 | 一级分类「中文」 | 二级分类「英文」 | 二级分类「中文」 | 风险等级 |
| :--- | :--- | :--- | :--- | :--- |
| Sanctions | 制裁 | Sanctioned Entity | 制裁实体 | **严重** |
| Sanctions | 制裁 | Sanctioned Jurisdiction | 制裁管辖区 | **严重** |
| Sanctions | 制裁 | Prohibited Entity（Singapore） | 发出限制的国家/地址 | **严重** |
| Terrorism Financing | 恐怖主义融资 | Terrorist Organization (Name) | 恐怖组织 (名称) | **严重** |
| Other Financial Crimes | 其他金额犯罪 | Suspected Money Laundering | 涉嫌洗钱 | **严重** |
| Public Freezing Action | 执法冻结 | Law Enforcement Freeze/Seizure | 执法机构 (名称) | **严重** |
| Illicit Markets | 非法市场 | Human Trafficking | 人口贩卖 | **严重** |
| Illicit Markets | 非法市场 | Illegal Services | 非法服务 | **严重** |
| Illicit Markets | 非法市场 | Child Sexual Abuse Material | 儿童虐待（CSAM） | **严重** |
| Cybercrime | 网络犯罪 | Hacker/Thief | 被盗资金 | 高风险 |
| Cybercrime | 网络犯罪 | Ransomware | 勒索软件 | 高风险 |
| Cybercrime | 网络犯罪 | Phishing | 网络钓鱼 | 高风险 |
| Cybercrime | 网络犯罪 | Ponzi | 庞氏骗局 | 高风险 |
| Cybercrime | 网络犯罪 | Pig Butchering | 杀猪盘 | 高风险 |
| Cybercrime | 网络犯罪 | Rug Pull | 项目方跑路 | 高风险 |
| Cybercrime | 网络犯罪 | Honeypot | 蜜罐合约 | 高风险 |
| Cybercrime | 网络犯罪 | Fake Presale | 虚假预售 | 高风险 |
| Cybercrime | 网络犯罪 | Black/Grey Industry | 黑/灰产交易 | 中风险 |
| Obfuscation | 混淆/隐私 | Mixers | 混币器 | 高风险 |
| Obfuscation | 混淆/隐私 | Privacy Wallet | 隐私钱包 | 高风险 |
| Obfuscation | 混淆/隐私 | Privacy Token | 隐私代币 | 高风险 |
| Obfuscation | 混淆/隐私 | Centralized Bridge | 中心化跨链桥服务 | 高风险 |
| Obfuscation | 混淆/隐私 | Crypto ATM/Kiosk | 加密货币ATM | 高风险 |
| Gambling | 博彩 | Unlicensed Gambling | 无牌照博彩 | 高风险 |
| High-Risk Entities | 高风险实体 | CEX in High-Risk Jurisdiction | 高风险地区交易所 | 高风险 |
| High-Risk Entities | 高风险实体 | Sanctioned CEX | 被制裁交易所 | 高风险 |
| High-Risk Entities | 高风险实体 | CEX with Weak AML/CFT Controls | 弱AML/CFT管控交易所 | 高风险 |
| High-Risk Entities | 高风险实体 | OTC Desk | 场外交易平台 | 高风险 |
| High-Risk Entities | 高风险实体 | High-Risk Bridges | 高风险跨链桥服务 | 高风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | CEX | 中心化交易所 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | TradFi | 传统金融机构 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | DeFi Protocol | 去中心化金融协议 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | DEX | 去中心化交易所 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | CDP | 抵押债仓 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Dex Aggregator | 去中心化交易所聚合器 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Derivatives | 衍生品协议 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Yield Protocol | 收益创造协议 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Lending Protocol | 借贷协议 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Liquid Staking Protocol | 流动性质押协议（链POS） | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | RWA | 现实世界资产映射上链 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Prediction Market | 预测市场 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Staking Protocol | 代币质押协议 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Bridges | 跨链桥服务 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | NFT Marketplaces | NFT市场 | 低风险 |
| Exchanges & DeFi | 交易所 & 去中心化金融协议 | Broker | 去中心化机构交易商 | 低风险 |
| Other Entities | 辅助类 | Web3 AI Protocol | Web3 的 AI协议 | 低风险 |
| Other Entities | 辅助类 | Stablecoin | 稳定币发行 | 低风险 |
| Other Entities | 辅助类 | Custodian | 资金托管服务商 | 低风险 |
| Other Entities | 辅助类 | Smart Contract Account | 智能合约账户 | 低风险 |
| Other Entities | 辅助类 | MEV Bots/Arbitrage | MEV机器人/套利 | 中风险 |
| Other Entities | 辅助类 | Mining Pools/Validators | 矿池/验证节点 | 低风险 |
| Other Entities | 辅助类 | Payments | 支付机构 | 低风险 |
| Other Entities | 辅助类 | DAO Treasury | DAO财政库 | 低风险 |
| Other Entities | 辅助类 | Charity/NGO | 慈善/非政府组织 | 低风险 |
| Other Entities | 辅助类 | Market Maker | 做市商 | 低风险 |
| Other Entities | 辅助类 | Asset Manager | 资产管理 | 低风险 |
| Other Entities | 辅助类 | Spam | 垃圾交易/空投 | 中风险 |
| Other Entities | 辅助类 | Multisig Wallet | 多签钱包 | 低风险 |
| Other Entities | 辅助类 | Self-custody Wallet | 自托管钱包 | 低风险 |
| Other Entities | 辅助类 | Custodial Wallet | 托管钱包 | 低风险 |
| Other Entities | 辅助类 | AA Wallet | AA钱包 | 低风险 |
| Other Entities | 辅助类 | Contract Deployer | 合约部署者 | 低风险 |
| Other Entities | 辅助类 | Token Address | 代币合约地址 | 低风险 |
| Other Entities | 辅助类 | Fund | 基金 | 低风险 |
| Other Entities | 辅助类 | Launchpad | 发射平台 | 低风险 |
| Other Entities | 辅助类 | Chain Infrastructure | 链基础设施 | 低风险 |
| Other Entities | 辅助类 | GameFi | 链游 | 低风险 |
| Other Entities | 辅助类 | SocialFi | 社交协议 | 低风险 |
| Other Entities | 辅助类 | Contract Address | 普通合约地址 | 低风险 |
| Other Entities | 辅助类 | Wallet Address | 普通钱包地址 | 低风险 |

path: requirements.txt
content: requests>=2.28.0
python-dotenv>=0.19.0


path: schema/rule_schema.json
content: {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "AML Rule List",
  "description": "A collection of Anti-Money Laundering (AML) and Counter-Terrorist Financing (CFT) rules categorized by business scenarios, mapped to TrustIn Graph API data structures.",
  "type": "array",
  "items": {
    "type": "object",
    "required": [
      "rule_id",
      "category",
      "name",
      "risk_level",
      "action"
    ],
    "properties": {
      "rule_id": {
        "type": "string",
        "description": "Unique identifier for the rule (e.g., ONB-001, DEP-002)"
      },
      "category": {
        "type": "string",
        "enum": ["Deposit", "Withdrawal", "CDD", "Ongoing Monitoring"],
        "description": "The business scenario this rule applies to"
      },
      "direction": {
        "type": "string",
        "enum": ["inflow", "outflow"],
        "description": "Which path direction this rule matches. Omit for direction-agnostic rules (e.g., self-tag checks, whitelist)."
      },
      "min_hops": {
        "type": "integer",
        "minimum": 1,
        "maximum": 10,
        "description": "Minimum hop distance (inclusive) for this rule to apply. Omit for rules that match any hop distance."
      },
      "max_hops": {
        "type": "integer",
        "minimum": 1,
        "maximum": 10,
        "description": "Maximum hop distance (inclusive) for this rule to apply. Omit for rules that match any hop distance."
      },
      "name": {
        "type": "string",
        "description": "Short, descriptive name of the rule"
      },
      "description": {
        "type": "string",
        "description": "Detailed explanation of what the rule detects and why"
      },
      "conditions": {
        "type": "array",
        "description": "List of logical conditions that trigger the rule based on graph data paths. Multiple conditions in this array are evaluated as 'AND'. For 'OR' logic, create a separate rule.",
        "items": {
          "type": "object",
          "properties": {
            "parameter": {
              "type": "string",
              "enum": [
                "target.tags.primary_category",
                "target.tags.secondary_category",
                "target.tags.risk_level",
                "target.daily_deposit_usd",
                "target.daily_withdrawal_usd",
                "path.hops_total",
                "path.amount",
                "path.risk_percentage",
                "path.risk_amount_usd",
                "path.node.tags.primary_category",
                "path.node.tags.secondary_category",
                "path.node.tags.risk_level"
              ],
              "description": "The specific JSON path in the TrustIn Graph API response being evaluated"
            },
            "operator": {
              "type": "string",
              "enum": [">", "<", ">=", "<=", "==", "!=", "CONTAINS", "IN", "NOT_IN"],
              "description": "Logical operator"
            },
            "value": {
              "type": ["string", "number", "boolean", "array"],
              "description": "The threshold or exact match value expected at the JSON path"
            },
            "unit": {
              "type": "string",
              "description": "Optional unit of measurement (e.g., 'USD', 'Hops', '%')"
            }
          },
          "required": ["parameter", "operator", "value"]
        }
      },
      "risk_level": {
        "type": "string",
        "enum": ["Low", "Medium", "High", "Severe"],
        "description": "The severity of the risk if triggered"
      },
      "action": {
        "type": "string",
        "enum": ["Freeze", "Reject", "EDD", "Review", "Warning", "Allow", "Whitelist"],
        "description": "The system or manual action required when the rule triggers"
      },
      "reference": {
        "type": "string",
        "description": "Citation of the regulatory clause or internal policy document"
      }
    }
  }
}


path: schema/screening_report_schema.json
content: {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "AML Screening Result Specification",
  "description": "Schema for the results returned by the TrustIn API and local amlclaw screening engine",
  "type": "object",
  "properties": {
    "chain": {
      "type": "string",
      "description": "Blockchain network name (e.g., Tron, Ethereum)"
    },
    "address": {
      "type": "string",
      "description": "Wallet address that was screened"
    },
    "direction": {
      "type": "string",
      "enum": ["inflow", "outflow", "all"],
      "description": "Direction of the trace calculation"
    },
    "risk_score": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100,
      "description": "Calculated risk score based on path/tags priority"
    },
    "risk_level": {
      "type": "string",
      "enum": ["Low", "Medium", "High", "Severe"],
      "description": "Categorical representation of the risk_score"
    },
    "recommendation": {
      "type": "string",
      "description": "Human-readable action recommendation"
    },
    "triggered_rules": {
      "type": "array",
      "description": "List of user-defined custom rules from rules.json that were triggered by the address graph data",
      "items": {
        "type": "object",
        "properties": {
          "rule_id": { "type": "string" },
          "name": { "type": "string" },
          "action": { "type": "string", "enum": ["Review", "EDD", "Reject", "Freeze", "Whitelist"] },
          "risk_level": { "type": "string" }
        }
      }
    }
  }
}


path: scripts/extract_risk_paths.py
content: #!/usr/bin/env python3
"""
extract_risk_paths.py
--------------------
Reads the raw graph JSON from `fetch_graph.py` and the user's `rules.json`.
Extracts every node within 1-5 hops that matches any rule condition.
Supports scenario-based filtering: only applies rules matching the business scenario.
Outputs a deduplicated, LLM-friendly `risk_paths_*.json` for report generation.
"""
import argparse
import json
import os
import sys
from datetime import datetime


# ---------------------------------------------------------------------------
# Scenario → Category mapping
# ---------------------------------------------------------------------------
SCENARIO_CATEGORIES = {
    "onboarding":  ["Deposit"],                  # onboarding = deposit rules (DEP-SELF-* + inflow + outflow history)
    "deposit":     ["Deposit"],
    "withdrawal":  ["Withdrawal"],
    "cdd":         ["CDD"],
    "monitoring":  ["Ongoing Monitoring"],
    "all":         None,                         # no filtering (legacy default)
}

# ---------------------------------------------------------------------------
# Scenario → allowed path directions (-1 = inflow, 1 = outflow)
# ---------------------------------------------------------------------------
SCENARIO_PATH_FILTER = {
    "onboarding":  None,    # both directions
    "deposit":     None,    # both directions (rules self-filter via direction field)
    "withdrawal":  [1],     # outflow only
    "cdd":         None,    # both directions
    "monitoring":  None,    # both directions
    "all":         None,    # both directions
}


def load_rules(rules_path: str):
    with open(rules_path, "r", encoding="utf-8") as f:
        return json.load(f)


def load_graph(graph_path: str):
    with open(graph_path, "r", encoding="utf-8") as f:
        return json.load(f)


def prioritize_tag(tags):
    """Return the tag dict with the lowest `priority` value."""
    if not tags:
        return None
    def pr(tag):
        try:
            return int(tag.get("priority", 9999))
        except Exception:
            return 9999
    return min(tags, key=pr)


# ---------------------------------------------------------------------------
# Condition parameters evaluable at the node level (path traversal).
# ---------------------------------------------------------------------------
NODE_LEVEL_PARAMS = {
    "path.node.tags.primary_category",
    "path.node.tags.secondary_category",
    "path.node.tags.risk_level",
}

# ---------------------------------------------------------------------------
# Condition parameters evaluable at the target level (target self-tags).
# ---------------------------------------------------------------------------
TARGET_LEVEL_PARAMS = {
    "target.tags.primary_category",
    "target.tags.secondary_category",
    "target.tags.risk_level",
}


def eval_condition(cond, node_tag, node_deep):
    """
    Evaluate a single condition against a node.
    Returns:
        True  — condition matches
        False — condition does not match
        None  — condition is not node-evaluable (skip)
    """
    param = cond.get("parameter", "")
    op = cond.get("operator", "")
    value = cond.get("value")

    if param not in NODE_LEVEL_PARAMS:
        return None  # not evaluable at node level — skip

    # --- Tag matching ---
    if param == "path.node.tags.primary_category":
        actual = node_tag.get("primary_category") if node_tag else None
        if actual is None:
            return False
        if op == "IN":
            return actual in value
        elif op == "==":
            return actual == value
        elif op == "!=":
            return actual != value
        elif op == "NOT_IN":
            return actual not in value
        return False

    if param == "path.node.tags.secondary_category":
        actual = node_tag.get("secondary_category") if node_tag else None
        if actual is None:
            return False
        if op == "IN":
            return actual in value
        elif op == "==":
            return actual == value
        elif op == "!=":
            return actual != value
        elif op == "NOT_IN":
            return actual not in value
        return False

    if param == "path.node.tags.risk_level":
        actual = node_tag.get("risk_level") if node_tag else None
        if actual is None:
            return False
        if op == "==":
            return actual == value
        elif op == "!=":
            return actual != value
        elif op == "IN":
            return actual in value
        return False

    return None


def eval_target_condition(cond, target_tag):
    """
    Evaluate a single target-level condition against a target tag.
    Returns:
        True  — condition matches
        False — condition does not match
        None  — condition is not target-evaluable (skip)
    """
    param = cond.get("parameter", "")
    op = cond.get("operator", "")
    value = cond.get("value")

    if param not in TARGET_LEVEL_PARAMS:
        return None

    if param == "target.tags.primary_category":
        actual = target_tag.get("primary_category") if target_tag else None
        if actual is None:
            return False
        if op == "IN":
            return actual in value
        elif op == "==":
            return actual == value
        elif op == "!=":
            return actual != value
        elif op == "NOT_IN":
            return actual not in value
        return False

    if param == "target.tags.secondary_category":
        actual = target_tag.get("secondary_category") if target_tag else None
        if actual is None:
            return False
        if op == "IN":
            return actual in value
        elif op == "==":
            return actual == value
        elif op == "!=":
            return actual != value
        elif op == "NOT_IN":
            return actual not in value
        return False

    if param == "target.tags.risk_level":
        actual = target_tag.get("risk_level") if target_tag else None
        if actual is None:
            return False
        if op == "==":
            return actual == value
        elif op == "!=":
            return actual != value
        elif op == "IN":
            return actual in value
        return False

    return None


def rule_has_target_conditions(rule):
    """Check if a rule contains any target-level conditions."""
    for cond in rule.get("conditions", []):
        if cond.get("parameter", "") in TARGET_LEVEL_PARAMS:
            return True
    return False


def rule_matches_target_tag(rule, target_tag):
    """
    Match a rule against a single target tag.
    Only evaluates target-level conditions (AND logic).
    Non-target conditions are skipped.
    """
    conditions = rule.get("conditions", [])
    if not conditions:
        return False

    target_conditions_evaluated = 0

    for cond in conditions:
        result = eval_target_condition(cond, target_tag)
        if result is None:
            continue
        target_conditions_evaluated += 1
        if not result:
            return False

    return target_conditions_evaluated > 0


def evaluate_target_rules(rules, target_tags):
    """
    Evaluate rules against the target address's own tags.
    Returns a list of findings: [{tag, matched_rules}]
    """
    target_rules = [r for r in rules if rule_has_target_conditions(r)]
    if not target_rules or not target_tags:
        return []

    findings = []
    for tag in target_tags:
        matched_rule_ids = []
        for rule in target_rules:
            if rule_matches_target_tag(rule, tag):
                matched_rule_ids.append(rule.get("rule_id"))
        if matched_rule_ids:
            findings.append({
                "tag": {
                    "primary_category": tag.get("primary_category", ""),
                    "secondary_category": tag.get("secondary_category", ""),
                    "tertiary_category": tag.get("tertiary_category", ""),
                    "quaternary_category": tag.get("quaternary_category", ""),
                    "risk_level": tag.get("risk_level", ""),
                },
                "matched_rules": sorted(matched_rule_ids),
            })

    return findings


def rule_applies_to_context(rule, path_dir, node_deep):
    """
    Check if a rule applies to the current path direction and hop distance.
    Uses top-level rule fields: direction, min_hops, max_hops.
    Rules without these fields match any context (direction-agnostic, hop-agnostic).
    """
    # Direction check: -1 = inflow, 1 = outflow
    rule_dir = rule.get("direction")
    if rule_dir:
        dir_map = {"inflow": -1, "outflow": 1}
        if dir_map.get(rule_dir) != path_dir:
            return False

    # Hop range check
    min_h = rule.get("min_hops")
    max_h = rule.get("max_hops")
    if min_h is not None and node_deep < min_h:
        return False
    if max_h is not None and node_deep > max_h:
        return False

    return True


def rule_matches_node(rule, node_tag, node_deep):
    """
    Match a rule against a node's tag and computed deep value.

    Logic:
    - Evaluate all node-level conditions (AND logic).
    - If ANY node-level condition fails → no match.
    - If ZERO node-level conditions exist → no match (rule is not node-evaluable).
    - Non-node conditions are skipped (LLM evaluates them later).
    """
    conditions = rule.get("conditions", [])
    if not conditions:
        return False

    node_conditions_evaluated = 0

    for cond in conditions:
        result = eval_condition(cond, node_tag, node_deep)
        if result is None:
            continue  # non-node-level condition, skip
        node_conditions_evaluated += 1
        if not result:
            return False  # AND logic: one fail = rule fails

    # Must have evaluated at least one node-level condition
    return node_conditions_evaluated > 0


def format_evidence_path(nodes, illicit_index, path_direction):
    """
    Format the evidence string for the fund flow.
    INFLOW (-1): [Source, ..., Target] — show from illicit node to target.
    OUTFLOW (1): [Target, ..., Destination] — show from target to illicit node.
    """
    if path_direction == -1:
        relevant_nodes = nodes[illicit_index:]
    elif path_direction == 1:
        relevant_nodes = nodes[:illicit_index + 1]
    else:
        relevant_nodes = nodes

    parts = []
    for i, n in enumerate(relevant_nodes):
        addr = n.get("address", "Unknown")
        amount = n.get("amount", 0)
        if amount is None:
            amount = 0

        tags = n.get("tags", [])
        label_str = ""
        if tags:
            best_tag = prioritize_tag(tags)
            if best_tag:
                lbl = (best_tag.get("quaternary_category")
                       or best_tag.get("tertiary_category")
                       or best_tag.get("secondary_category")
                       or best_tag.get("primary_category"))
                if lbl:
                    label_str = f" ({lbl})"

        if i > 0:
            parts.append(f"--({amount} USD)-->")
        parts.append(f"[{addr}{label_str}]")

    return " ".join(parts)


def compute_true_deep(node_index, num_nodes, path_dir, raw_deep):
    """
    Compute hop distance from target based on position in path array.
    Falls back to positional calculation when API deep field is unreliable (all zeros).

    Inflow (-1): path = [Source(far), ..., Target(near)]
        → hop distance = num_nodes - 1 - node_index
    Outflow (1): path = [Target(near), ..., Dest(far)]
        → hop distance = node_index
    """
    if path_dir == -1:  # inflow
        return num_nodes - 1 - node_index
    else:  # outflow
        return node_index


def extract_risk_paths(graph_data, rules, max_depth=5, scenario="all"):
    """
    Core extraction: walk every path, compute true hop distances,
    match nodes against rules, deduplicate by address.
    Supports scenario-based category filtering and path direction filtering.
    """
    data = graph_data.get("graph_data", {}).get("data", {})
    target_address = graph_data.get("address", "")

    # --- Scenario: filter rules by category ---
    categories = SCENARIO_CATEGORIES.get(scenario)
    rules_total_loaded = len(rules)
    if categories:
        rules = [r for r in rules if r.get("category") in categories]
    rules_after_filter = len(rules)

    # --- Scenario: determine allowed path directions ---
    allowed_dirs = SCENARIO_PATH_FILTER.get(scenario)

    # --- Target self-tag evaluation ---
    target_tags_raw = data.get("tags", [])
    target_findings = evaluate_target_rules(rules, target_tags_raw)
    target_self_matched_rules = set()
    for tf in target_findings:
        target_self_matched_rules.update(tf["matched_rules"])

    # --- Path traversal ---
    findings = {}  # address -> { tag, deep_min, matched_rules: set, evidence_paths: [], occurrences }

    all_paths = data.get("paths", [])
    paths_direction_filtered = 0

    for path_idx, path in enumerate(all_paths):
        nodes = path.get("path", [])
        path_dir = path.get("direction", -1)

        if not nodes:
            continue

        # Filter paths by scenario direction
        if allowed_dirs and path_dir not in allowed_dirs:
            paths_direction_filtered += 1
            continue

        num_nodes = len(nodes)

        for node_idx, node in enumerate(nodes):
            addr = node.get("address", "")

            # Skip the target address itself — it's the investigation subject
            if addr == target_address:
                continue

            raw_deep = node.get("deep")
            true_deep = compute_true_deep(node_idx, num_nodes, path_dir, raw_deep)

            if true_deep is None or true_deep < 1 or true_deep > max_depth:
                continue

            tag = prioritize_tag(node.get("tags", []))
            if not tag:
                continue

            # Match rules (check direction + hop range, then node-level conditions)
            matched_rule_ids = []
            for rule in rules:
                if not rule_applies_to_context(rule, path_dir, true_deep):
                    continue
                if rule_matches_node(rule, tag, true_deep):
                    matched_rule_ids.append(rule.get("rule_id"))

            if not matched_rule_ids:
                continue

            # Build evidence path string
            evidence = format_evidence_path(nodes, node_idx, path_dir)

            # Aggregate into findings dict
            key = addr
            if key not in findings:
                findings[key] = {
                    "address": addr,
                    "min_deep": true_deep,
                    "tag": {
                        "primary_category": tag.get("primary_category", ""),
                        "secondary_category": tag.get("secondary_category", ""),
                        "tertiary_category": tag.get("tertiary_category", ""),
                        "quaternary_category": tag.get("quaternary_category", ""),
                        "risk_level": tag.get("risk_level", ""),
                    },
                    "matched_rules": set(),
                    "evidence_paths": [],
                    "occurrences": 0,
                }

            entry = findings[key]
            entry["matched_rules"].update(matched_rule_ids)
            entry["min_deep"] = min(entry["min_deep"], true_deep)
            entry["occurrences"] += 1

            # Keep evidence paths but cap per entity to avoid explosion
            if len(entry["evidence_paths"]) < 3:
                entry["evidence_paths"].append({
                    "path_index": path_idx,
                    "deep": true_deep,
                    "flow": evidence,
                })

    # Convert sets to sorted lists and sort findings by severity
    severity_order = {"severe": 0, "high": 1, "medium": 2, "low": 3}
    result = []
    for f in findings.values():
        f["matched_rules"] = sorted(f["matched_rules"])
        result.append(f)

    result.sort(key=lambda x: (
        severity_order.get(x["tag"].get("risk_level", "low"), 3),
        x["min_deep"],
    ))

    # Build summary
    all_triggered = set()
    for f in result:
        all_triggered.update(f["matched_rules"])
    # Include target self-matched rules in triggered set
    all_triggered.update(target_self_matched_rules)

    highest_severity = "Low"
    for f in result:
        rl = f["tag"].get("risk_level", "low").lower()
        if rl in ("severe", "high") and severity_order.get(rl, 3) < severity_order.get(highest_severity.lower(), 3):
            highest_severity = {"severe": "Severe", "high": "High", "medium": "Medium", "low": "Low"}.get(rl, "Low")

    # Check rules for highest action
    rule_severity = {}
    for rule in rules:
        rule_severity[rule["rule_id"]] = rule.get("risk_level", "Low")
    for rid in all_triggered:
        rs = rule_severity.get(rid, "Low")
        if severity_order.get(rs.lower(), 3) < severity_order.get(highest_severity.lower(), 3):
            highest_severity = rs

    summary = {
        "scenario": scenario,
        "categories_applied": categories if categories else ["ALL"],
        "total_paths_analyzed": len(all_paths),
        "paths_direction_filtered": paths_direction_filtered,
        "unique_risk_entities": len(result),
        "rules_loaded": rules_after_filter,
        "rules_total_available": rules_total_loaded,
        "rules_triggered": sorted(all_triggered),
        "highest_severity": highest_severity,
    }

    return result, summary, target_findings, target_tags_raw


def main():
    parser = argparse.ArgumentParser(description="Extract risk-relevant paths within 1-5 hops.")
    parser.add_argument("--graph", required=True, help="Path to raw_graph JSON file.")
    parser.add_argument("--rules", default="rules.json", help="Path to rules.json (default: ./rules.json).")
    parser.add_argument("--max-depth", type=int, default=5, help="Maximum hop depth to consider.")
    parser.add_argument("--scenario", choices=list(SCENARIO_CATEGORIES.keys()), default="all",
                        help="Business scenario filter (default: all).")
    args = parser.parse_args()

    if not os.path.isfile(args.graph):
        print(json.dumps({"error": f"Graph file not found: {args.graph}"}))
        sys.exit(1)
    if not os.path.isfile(args.rules):
        print(json.dumps({"error": f"Rules file not found: {args.rules}"}))
        sys.exit(1)

    graph = load_graph(args.graph)
    rules = load_rules(args.rules)

    risk_entities, summary, target_findings, target_tags_raw = extract_risk_paths(
        graph, rules, max_depth=args.max_depth, scenario=args.scenario
    )

    # Prepare output path — reuse the same timestamp from the raw_graph filename
    base_name = os.path.basename(args.graph)
    stem = base_name.replace(".json", "").replace("raw_graph_", "")
    out_name = f"risk_paths_{stem}.json"
    out_dir = os.path.join(os.getcwd(), "graph_data")
    os.makedirs(out_dir, exist_ok=True)
    out_path = os.path.join(out_dir, out_name)

    # Build target block with self-tags and self-matched rules
    target_self_matched = set()
    target_tags_formatted = []
    for tag in target_tags_raw:
        target_tags_formatted.append({
            "primary_category": tag.get("primary_category", ""),
            "secondary_category": tag.get("secondary_category", ""),
            "tertiary_category": tag.get("tertiary_category", ""),
            "quaternary_category": tag.get("quaternary_category", ""),
            "risk_level": tag.get("risk_level", ""),
        })
    for tf in target_findings:
        target_self_matched.update(tf["matched_rules"])

    output = {
        "target": {
            "chain": graph.get("chain", ""),
            "address": graph.get("address", ""),
            "tags": target_tags_formatted,
            "self_matched_rules": sorted(target_self_matched),
        },
        "scenario": args.scenario,
        "summary": summary,
        "risk_entities": risk_entities,
    }

    with open(out_path, "w", encoding="utf-8") as f:
        json.dump(output, f, indent=2, ensure_ascii=False)
    print(json.dumps({"status": "success", "output": out_path, "count": len(risk_entities),
                       "scenario": args.scenario, "target_self_hits": len(target_self_matched)}))


if __name__ == "__main__":
    main()


path: scripts/fetch_graph.py
content: """
fetch_graph.py - A lightweight script to interact with the TrustIn API and retrieve
the raw transaction graph data for a given blockchain address.

This script does NOT perform rule evaluation. It only fetches the data and saves it
to a JSON file for downstream LLM or system consumption.
"""
import os
import json
import argparse
from typing import Dict
from datetime import datetime

from trustin_api import TrustInAPI

try:
    from dotenv import load_dotenv
    load_dotenv()
except ImportError:
    pass

def fetch_graph(chain: str, address: str, direction: str = "inflow", inflow_hops: int = 3, outflow_hops: int = 3, api_key: str = None, min_timestamp: int = None, max_timestamp: int = None, max_nodes_per_hop: int = 100) -> Dict:
    """Fetches graph data for an address using TrustInAPI."""
    start_time = datetime.now()
    
    # Apply defaults for timestamps (4 years ago and now) if not provided
    if not max_timestamp:
        max_timestamp = int(start_time.timestamp() * 1000)
    if not min_timestamp:
        four_years_ago = start_time.timestamp() - (4 * 365 * 24 * 60 * 60)
        min_timestamp = int(four_years_ago * 1000)
        
    try:
        api = TrustInAPI([REDACTED_SECRET])
        # TrustIn API automatically uses async_detect underneath
        kwargs = {
            "inflow_hops": inflow_hops, 
            "outflow_hops": outflow_hops,
            "max_nodes_per_hop": max_nodes_per_hop,
            "min_timestamp": min_timestamp,
            "max_timestamp": max_timestamp
        }
        
        result = api.kya_pro_detect(chain, address, **kwargs)
        
        # Package the raw graph details returned by the API
        response = {
            "chain": chain,
            "address": address,
            "direction": direction,
            "hops_requested": {
                "inflow": inflow_hops,
                "outflow": outflow_hops
            },
            "parameters": {
                "max_nodes_per_hop": max_nodes_per_hop,
                "min_timestamp_ms": min_timestamp,
                "max_timestamp_ms": max_timestamp
            },
            "timestamp": datetime.now().isoformat(),
            "execution_time": str(datetime.now() - start_time),
            "graph_data": result.details # The raw parsed JSON graph
        }
        return response
        
    except Exception as e:
        print(f"[ERROR] Failed to fetch graph: {str(e)}")
        import traceback
        traceback.print_exc()
        return {}

def main():
    parser = argparse.ArgumentParser(description="Fetch TrustIn raw graph data.")
    parser.add_argument("chain", help="Blockchain network (e.g., Tron, Ethereum)")
    parser.add_argument("address", help="Wallet address to investigate")
    parser.add_argument("--direction", choices=["inflow", "outflow", "all"], default="inflow", help="Trace direction")
    parser.add_argument("--inflow-hops", type=int, default=3, help="Inflow depth (default: 3)")
    parser.add_argument("--outflow-hops", type=int, default=3, help="Outflow depth (default: 3)")
    parser.add_argument("--max-nodes", type=int, default=100, help="Max nodes per hop (default: 100, max: 1000)")
    parser.add_argument("--min-timestamp", type=int, help="Min timestamp in milliseconds (default: 4 years ago)")
    parser.add_argument("--max-timestamp", type=int, help="Max timestamp in milliseconds (default: now)")
    parser.add_argument("--api-key", help="TrustIn API Key (optional if in env)")
    
    args = parser.parse_args()
    
    print(f"📡 Fetching Graph for {args.chain} - {args.address}...")
    print(f"   Direction: {args.direction.upper()} | Inflow: {args.inflow_hops} hops | Outflow: {args.outflow_hops} hops | Max Nodes: {args.max_nodes}")
    
    result = fetch_graph(
        chain=args.chain,
        address=args.address,
        direction=args.direction,
        inflow_hops=args.inflow_hops,
        outflow_hops=args.outflow_hops,
        max_nodes_per_hop=args.max_nodes,
        [REDACTED_SECRET],
        min_timestamp=args.min_timestamp,
        max_timestamp=args.max_timestamp
    )
    
    if result and result.get("graph_data"):
        # Create directories in the current working directory
        reports_dir = os.path.join(os.getcwd(), "reports")
        graph_dir = os.path.join(os.getcwd(), "graph_data")
        os.makedirs(reports_dir, exist_ok=True)
        os.makedirs(graph_dir, exist_ok=True)
        
        timestamp_str = datetime.now().strftime("%Y%m%d_%H%M%S")
        json_path = os.path.join(graph_dir, f"raw_graph_{args.address}_{timestamp_str}.json")
        with open(json_path, "w", encoding="utf-8") as f:
            json.dump(result, f, indent=2, ensure_ascii=False)
            
        print(f"\n✅ SUCCESS: Raw Graph JSON saved to: {json_path}")
        print(f"👉 Now hand over to the LLM Agent to evaluate against rules.json!")
    else:
        print("\n❌ FAILED: Could not retrieve graph data.")
        exit(1)

if __name__ == "__main__":
    main()


path: scripts/run_screening.py
content: #!/usr/bin/env python3
"""
run_screening.py
----------------
Orchestrates the full AML address-screening pipeline:
1. Fetches raw graph via TrustIn API (up to 5 hops).
2. Extracts risk-relevant paths (1 to 5 hops) by cross-referencing rules.json.
3. Provides instructions for the final LLM report generation.

Supports --scenario to restrict analysis to a specific business context
(onboarding, deposit, withdrawal, cdd, monitoring, or all).
"""

import argparse
import subprocess
import os
import json
import sys
from datetime import datetime

# ---------------------------------------------------------------------------
# Default fetch direction per scenario (used when user omits --direction)
# ---------------------------------------------------------------------------
SCENARIO_DIRECTION_DEFAULTS = {
    "onboarding":  "all",
    "deposit":     "all",
    "withdrawal":  "outflow",
    "cdd":         "all",
    "monitoring":  "all",
    "all":         "all",
}

SCENARIO_CHOICES = list(SCENARIO_DIRECTION_DEFAULTS.keys())


def main():
    parser = argparse.ArgumentParser(description="Run full AML screening pipeline (Fetch -> Extract).")
    parser.add_argument("chain", help="Blockchain network (e.g., Tron, Ethereum)")
    parser.add_argument("address", help="Address to investigate")
    parser.add_argument("--direction", choices=["inflow", "outflow", "all"], default=None,
                        help="Trace direction (auto-set by scenario if omitted)")
    parser.add_argument("--scenario", choices=SCENARIO_CHOICES, default="all",
                        help="Business scenario filter (default: all)")
    parser.add_argument("--inflow-hops", type=int, default=3, help="Inflow hop depth")
    parser.add_argument("--outflow-hops", type=int, default=3, help="Outflow hop depth")
    parser.add_argument("--max-nodes", type=int, default=100, help="Max nodes per hop")
    parser.add_argument("--min-timestamp", type=int, help="Min timestamp (ms)")
    parser.add_argument("--max-timestamp", type=int, help="Max timestamp (ms)")
    parser.add_argument("--rules-config", default=os.path.join(os.getcwd(), "rules.json"), help="Path to rules.json")
    parser.add_argument("--max-depth", type=int, help="Deprecated (use --inflow-hops/--outflow-hops)")
    args = parser.parse_args()

    # Handle legacy --max-depth
    if args.max_depth is not None:
        inflow = outflow = args.max_depth
    else:
        inflow = args.inflow_hops
        outflow = args.outflow_hops

    # Auto-set direction from scenario if user didn't specify
    direction = args.direction
    if direction is None:
        direction = SCENARIO_DIRECTION_DEFAULTS.get(args.scenario, "all")

    scenario_label = args.scenario.upper()

    print("\n" + "="*60)
    print(f"  Scenario: {scenario_label} | Direction: {direction.upper()}")
    print("="*60)

    print(f"\n[STEP 1/3] Fetching Raw Graph (Inflow: {inflow} hops, Outflow: {outflow} hops)")
    print("-"*60)

    script_dir = os.path.dirname(os.path.abspath(__file__))
    fetch_script = os.path.join(script_dir, "fetch_graph.py")

    fetch_cmd = [
        "python3", fetch_script,
        args.chain, args.address,
        "--direction", direction,
        "--inflow-hops", str(inflow),
        "--outflow-hops", str(outflow),
        "--max-nodes", str(args.max_nodes)
    ]
    if args.min_timestamp:
        fetch_cmd.extend(["--min-timestamp", str(args.min_timestamp)])
    if args.max_timestamp:
        fetch_cmd.extend(["--max-timestamp", str(args.max_timestamp)])

    try:
        subprocess.run(fetch_cmd, check=True)
    except subprocess.CalledProcessError:
        print("FAILED: API extraction aborted.")
        sys.exit(1)

    # Locate the most recently generated raw graph file
    graph_dir = os.path.join(os.getcwd(), "graph_data")
    if not os.path.exists(graph_dir):
        print("FAILED: Directory graph_data/ not found.")
        sys.exit(1)

    raw_files = sorted([f for f in os.listdir(graph_dir) if f.startswith(f"raw_graph_{args.address}_") and f.endswith(".json")])
    if not raw_files:
        print("FAILED: Could not find newly generated raw graph file.")
        sys.exit(1)

    raw_path = os.path.join(graph_dir, raw_files[-1])

    print(f"\n[STEP 2/3] Extracting Risk Paths (Scenario: {scenario_label}, Layers 1-{max(inflow, outflow)})")
    print("-"*60)

    extract_script = os.path.join(script_dir, "extract_risk_paths.py")
    rules_path = args.rules_config

    if not os.path.exists(rules_path):
        print("\n" + "="*60)
        print("  NO COMPLIANCE RULES FOUND")
        print("="*60)
        print(f"\n  rules.json not found at: {rules_path}")
        print("\n  You need a rules.json policy file before screening.")
        print("  Quick fix — copy a default ruleset:\n")
        skill_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
        print(f"    cp {skill_root}/defaults/rulesets/singapore_mas.json ./rules.json")
        print(f"    cp {skill_root}/defaults/rulesets/hong_kong_sfc.json ./rules.json")
        print(f"    cp {skill_root}/defaults/rulesets/dubai_vara.json ./rules.json\n")
        print("  Or generate custom rules via the AMLClaw rule generation mode.")
        print("="*60 + "\n")
        sys.exit(1)

    extract_cmd = [
        "python3", extract_script,
        "--graph", raw_path,
        "--rules", rules_path,
        "--max-depth", str(max(inflow, outflow)),
        "--scenario", args.scenario,
    ]

    try:
        result = subprocess.run(extract_cmd, capture_output=True, text=True, check=True)
        # Parse output from extract_risk_paths.py
        for line in result.stdout.split('\n'):
            if line.startswith('{"status": "success"'):
                out_data = json.loads(line)
                risk_path_file = out_data["output"]
                path_count = out_data["count"]
                scenario_used = out_data.get("scenario", "all")
                target_self_hits = out_data.get("target_self_hits", 0)
                print(f"Extracted {path_count} unique risk entities (scenario: {scenario_used}).")
                if target_self_hits > 0:
                    print(f"  >> Target address self-check: {target_self_hits} rule(s) triggered on target's own tags.")
                break
        else:
            print("Warning: Could not parse exact path count, but extraction completed.")
            # Fallback path finding
            risk_files = sorted([f for f in os.listdir(graph_dir) if f.startswith(f"risk_paths_{args.address}_") and f.endswith(".json")])
            risk_path_file = os.path.join(graph_dir, risk_files[-1]) if risk_files else "UNKNOWN"

    except subprocess.CalledProcessError as e:
        print("FAILED: Python extraction failed.")
        print(e.stderr)
        sys.exit(1)

    print(f"\n[STEP 3/3] AI Agent Evaluation Handoff")
    print("-"*60)
    print("Data extraction is complete! The risk data has been heavily condensed to prevent LLM hallucination and context-loss.")
    print(f"\nNEXT STEP FOR AI AGENT:")
    print(f"1. Read the parsed risk evidence: `{risk_path_file}`")
    print(f"2. Read the rule framework: `{rules_path}`")
    print(f"3. Strictly follow instructions in `prompts/evaluation_prompt.md` to write the final Markdown report.")

if __name__ == "__main__":
    main()


path: scripts/trustin_api.py
content: """
TrustIn API integration for AML address screening.

This module provides integration with TrustIn's KYA (Know Your Address) API
for blockchain address risk assessment.
"""

import os
import json
import requests
from typing import Dict, Optional, Any
from dataclasses import dataclass
from datetime import datetime

@dataclass
class KYAResult:
    """Result from TrustIn KYA API."""
    risk_score: int
    risk_level: str
    recommendation: str
    details: Dict[str, Any]
    raw_response: Optional[Dict] = None
    error: Optional[str] = None

class TrustInAPI:
    """Client for TrustIn API (Async Tasks)."""
    
    BASE_URL = "https://api.trustin-webui-dev.com/api/v2/investigate"
    
    def __init__(self, [REDACTED_SECRET] = None):
        """
        Initialize TrustIn API client.
        
        Args:
            [REDACTED_SECRET] API key. Optional — works without key (desensitized mode).
        """
        self.[REDACTED_SECRET] or os.getenv("TRUSTIN_API_KEY") or ""
        # No raise — works without key in desensitized mode
        
        self.session = requests.Session()
        self.session.headers.update({
            "Content-Type": "text/plain",
            "User-Agent": "amlclaw-address-screening/0.1.0"
        })
    
    def _make_request(self, endpoint: str, data: Dict, require_auth: bool = False) -> Dict:
        """Make request to TrustIn API."""
        url = f"{self.BASE_URL}/{endpoint}"
        if self.api_key:
            url += f"?[REDACTED_SECRET]"
            
        try:
            # The API expects raw string payload in text/plain format according to curl
            response = self.session.post(url, data=json.dumps(data), timeout=30)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.Timeout:
            raise Exception("TrustIn API request timed out")
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 401:
                raise Exception("Invalid authorization (Check API Key)")
            else:
                raise Exception(f"TrustIn API error: {e}")
        except json.JSONDecodeError:
            raise Exception("Invalid response from TrustIn API")

    def _wait_for_task(self, task_id: int, max_retries: int = 30) -> bool:
        """Poll get_status until finished."""
        import time
        for _ in range(max_retries):
            res = self._make_request("get_status", {"task_id": task_id}, require_auth=True)
            if res.get("code") == 0 and res.get("data") == "finished":
                return True
            time.sleep(2)
        return False

    def async_detect(self, chain_name: str, address: str, **kwargs) -> KYAResult:
        """Execute the asynchronous submit->poll->result pipeline."""
        chain_mapping = {
            "Tron": "Tron",
            "Ethereum": "Ethereum",
            "Bitcoin": "Bitcoin",
            "Solana": "Solana"
        }
        
        if chain_name not in chain_mapping:
            raise ValueError(f"Unsupported chain for TrustIn API: {chain_name}")

        submit_payload = {
            "chain_name": chain_mapping[chain_name],
            "address": address,
            "inflow_hops": kwargs.get("inflow_hops", 3),
            "outflow_hops": kwargs.get("outflow_hops", 3),
            "max_nodes_per_hop": kwargs.get("max_nodes_per_hop", 100)
        }
        
        if kwargs.get("min_timestamp"):
            submit_payload["min_timestamp"] = kwargs["min_timestamp"]
        if kwargs.get("max_timestamp"):
            submit_payload["max_timestamp"] = kwargs["max_timestamp"]
        
        try:
            submit_res = self._make_request("submit_task", submit_payload)
            task_id = submit_res.get("data")
            if submit_res.get("code") != 0 or not task_id:
                raise Exception(f"Failed to submit task: {submit_res.get('msg')}")

            # Polling
            if not self._wait_for_task(task_id):
                raise Exception(f"Task {task_id} timed out while processing.")

            # Get Result
            result_payload = {
                "task_id": task_id,
                "token": "usdt" # Defaulting to usdt based on example
            }
            final_res = self._make_request("get_result", result_payload, require_auth=True)
            
            if final_res.get("code") == 0:
                raw_data = final_res.get("data", {})
                
                # The 'data' field might be stringified JSON
                if isinstance(raw_data, str):
                    try:
                        raw_data = json.loads(raw_data)
                    except json.JSONDecodeError:
                        raw_data = {}
                
                # Support the new dict wrapper containing inflow_total_amount
                if isinstance(raw_data, dict):
                    raw_graph = raw_data.get("graph", raw_data.get("paths", raw_data))
                else:
                    raw_graph = raw_data
                
                # Heuristically calculate risk score from raw graph tags priority
                max_priority = 4
                risk_tags = set()
                
                # Helper to process tags
                def process_tags(tags_list):
                    nonlocal max_priority
                    for tag in tags_list:
                        if isinstance(tag, dict):
                            prio = tag.get("priority", 4)
                            risk_tags.add(tag.get("primary_category", "Unknown"))
                            if prio < max_priority:
                                max_priority = prio
                
                if isinstance(raw_graph, list):
                    for flow in raw_graph:
                        if isinstance(flow, dict):
                            process_tags(flow.get("tags", []))
                            for node in flow.get("path", []):
                                if isinstance(node, dict):
                                    process_tags(node.get("tags", []))
                elif isinstance(raw_graph, dict):
                    process_tags(raw_graph.get("tags", []))
                    for node in raw_graph.get("path", []):
                        if isinstance(node, dict):
                            process_tags(node.get("tags", []))
                
                # Priority 1: Critical (100), Priority 2: High (80), Priority 3: Medium (60), Priority 4: Low (20)
                risk_score_map = {1: 100, 2: 80, 3: 60, 4: 20}
                risk_score = risk_score_map.get(max_priority, 20)
                
                recommendation = "No specific risk tags identified"
                if risk_tags:
                    recommendation = f"Risk tags: {', '.join(list(risk_tags)[:3])}"

                if risk_score <= 20:
                    risk_level = "LOW"
                elif risk_score <= 40:
                    risk_level = "MEDIUM_LOW"
                elif risk_score <= 60:
                    risk_level = "MEDIUM"
                elif risk_score <= 80:
                    risk_level = "HIGH"
                else:
                    risk_level = "CRITICAL"

                return KYAResult(
                    risk_score=risk_score,
                    risk_level=risk_level,
                    recommendation=recommendation,
                    details=final_res,
                    raw_response=final_res
                )
            else:
                error_msg = final_res.get("msg", "Unknown API error")
                raise Exception(f"Failed to fetch result: {error_msg}")

        except Exception as e:
            import traceback
            traceback.print_exc()
            return KYAResult(
                risk_score=50,
                risk_level="UNKNOWN",
                recommendation=f"API Error/Fallback: {str(e)}",
                details={"api_error": str(e), "fallback": True},
                error=str(e)
            )

    def kya_lite_detect(self, chain_name: str, address: str) -> KYAResult:
        """Fallback wrapper, using async_detect under the hood with 1 hop."""
        return self.async_detect(chain_name, address, inflow_hops=1, outflow_hops=1)
    
    def kya_pro_detect(self, chain_name: str, address: str, **kwargs) -> KYAResult:
        """Wrapper to async_detect"""
        return self.async_detect(chain_name, address, **kwargs)

# Helper functions for direct usage
def screen_with_trustin(
    chain: str,
    address: str,
    [REDACTED_SECRET] = None,
    use_pro: bool = False,
    **kwargs
) -> Dict:
    """
    Convenience function to screen address with TrustIn API.
    
    Args:
        chain: Blockchain network
        address: Wallet address
        [REDACTED_SECRET] API key (optional)
        use_pro: Use KYA Pro instead of KYA Lite
        **kwargs: Additional parameters for KYA Pro
    
    Returns:
        Dictionary with screening results
    """
    api = TrustInAPI([REDACTED_SECRET])
    
    if use_pro:
        result = api.kya_pro_detect(chain, address, **kwargs)
    else:
        result = api.kya_lite_detect(chain, address)
    
    return {
        "risk_score": result.risk_score,
        "risk_level": result.risk_level,
        "recommendation": result.recommendation,
        "details": result.details,
        "api_used": True,
        "api_error": result.error,
        "timestamp": datetime.now().isoformat()
    }

# Export for easy import
__all__ = [
    "TrustInAPI",
    "KYAResult",
    "screen_with_trustin"
]

path: scripts/validate_rules.py
content: #!/usr/bin/env python3
"""
validate_rules.py
-----------------
Validates rules.json against the rule_schema.json JSON Schema
and checks that condition values use valid TrustIn AML labels.

Usage:
    python3 amlclaw/aml-rule-generator/scripts/validate_rules.py [rules.json]
"""

import json
import sys
import os
import re

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
SKILL_DIR = os.path.dirname(SCRIPT_DIR)  # amlclaw/
SCHEMA_PATH = os.path.join(SKILL_DIR, "schema", "rule_schema.json")
LABELS_PATH = os.path.join(SKILL_DIR, "references", "trustin-labels.md")


def load_json(path):
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def parse_trustin_labels(labels_path):
    """Extract valid primary_category and secondary_category values from the Trustin AML labels Markdown table."""
    primary_categories = set()
    secondary_categories = set()

    if not os.path.exists(labels_path):
        print(f"  WARNING: Labels file not found at {labels_path}, skipping tag validation")
        return primary_categories, secondary_categories

    with open(labels_path, "r", encoding="utf-8") as f:
        content = f.read()

    for line in content.splitlines():
        line = line.strip()
        if not line.startswith("|") or line.startswith("| :") or line.startswith("| 一级"):
            continue
        cols = [c.strip() for c in line.split("|")]
        # cols: ['', primary_en, primary_cn, secondary_en, secondary_cn, risk, '']
        if len(cols) >= 6:
            primary_en = cols[1].strip()
            secondary_en = cols[3].strip()
            if primary_en and primary_en != "一级分类「英文」":
                primary_categories.add(primary_en)
            if secondary_en and secondary_en != "二级分类「英文」":
                secondary_categories.add(secondary_en)

    return primary_categories, secondary_categories


def validate_schema_structure(rules, schema):
    """Validate rules against the JSON Schema structure (lightweight, no jsonschema dependency)."""
    errors = []

    if not isinstance(rules, list):
        errors.append("Root element must be a JSON array")
        return errors

    valid_categories = schema["items"]["properties"]["category"]["enum"]
    valid_risk_levels = schema["items"]["properties"]["risk_level"]["enum"]
    valid_actions = schema["items"]["properties"]["action"]["enum"]
    valid_parameters = schema["items"]["properties"]["conditions"]["items"]["properties"]["parameter"]["enum"]
    valid_operators = schema["items"]["properties"]["conditions"]["items"]["properties"]["operator"]["enum"]
    required_fields = schema["items"]["required"]

    for i, rule in enumerate(rules):
        prefix = f"Rule [{i}] (id={rule.get('rule_id', '???')})"

        # Required fields
        for field in required_fields:
            if field not in rule:
                errors.append(f"{prefix}: missing required field '{field}'")

        # Enum validation
        if "category" in rule and rule["category"] not in valid_categories:
            errors.append(f"{prefix}: invalid category '{rule['category']}'. Valid: {valid_categories}")

        if "risk_level" in rule and rule["risk_level"] not in valid_risk_levels:
            errors.append(f"{prefix}: invalid risk_level '{rule['risk_level']}'. Valid: {valid_risk_levels}")

        if "action" in rule and rule["action"] not in valid_actions:
            errors.append(f"{prefix}: invalid action '{rule['action']}'. Valid: {valid_actions}")

        # New V2 fields validation
        if "direction" in rule:
            if rule["direction"] not in ("inflow", "outflow"):
                errors.append(f"{prefix}: invalid direction '{rule['direction']}'. Valid: ['inflow', 'outflow']")
        if "min_hops" in rule:
            if not isinstance(rule["min_hops"], int) or rule["min_hops"] < 1:
                errors.append(f"{prefix}: min_hops must be a positive integer, got '{rule['min_hops']}'")
        if "max_hops" in rule:
            if not isinstance(rule["max_hops"], int) or rule["max_hops"] < 1:
                errors.append(f"{prefix}: max_hops must be a positive integer, got '{rule['max_hops']}'")
        if "min_hops" in rule and "max_hops" in rule:
            if isinstance(rule["min_hops"], int) and isinstance(rule["max_hops"], int):
                if rule["min_hops"] > rule["max_hops"]:
                    errors.append(f"{prefix}: min_hops ({rule['min_hops']}) > max_hops ({rule['max_hops']})")

        # Conditions validation
        if "conditions" in rule:
            if not isinstance(rule["conditions"], list):
                errors.append(f"{prefix}: 'conditions' must be an array")
            else:
                for j, cond in enumerate(rule["conditions"]):
                    cprefix = f"{prefix} condition[{j}]"
                    for req in ["parameter", "operator", "value"]:
                        if req not in cond:
                            errors.append(f"{cprefix}: missing required field '{req}'")
                    if "parameter" in cond and cond["parameter"] not in valid_parameters:
                        errors.append(f"{cprefix}: invalid parameter '{cond['parameter']}'")
                    if "operator" in cond and cond["operator"] not in valid_operators:
                        errors.append(f"{cprefix}: invalid operator '{cond['operator']}'")

    return errors


def validate_rule_id_uniqueness(rules):
    """Check that all rule_ids are unique."""
    errors = []
    seen = {}
    for i, rule in enumerate(rules):
        rid = rule.get("rule_id")
        if rid is None:
            continue
        if rid in seen:
            errors.append(f"Duplicate rule_id '{rid}' at indices {seen[rid]} and {i}")
        else:
            seen[rid] = i
    return errors


def validate_tag_values(rules, primary_categories, secondary_categories):
    """Check that condition values referencing tag categories use valid TrustIn labels."""
    errors = []
    if not primary_categories and not secondary_categories:
        return errors  # Skip if labels not loaded

    tag_params = {
        "target.tags.primary_category": primary_categories,
        "target.tags.secondary_category": secondary_categories,
        "path.node.tags.primary_category": primary_categories,
        "path.node.tags.secondary_category": secondary_categories,
    }

    for i, rule in enumerate(rules):
        prefix = f"Rule [{i}] (id={rule.get('rule_id', '???')})"
        for j, cond in enumerate(rule.get("conditions", [])):
            param = cond.get("parameter", "")
            if param in tag_params:
                valid_tags = tag_params[param]
                value = cond.get("value")
                # Handle both single string and array values
                values = value if isinstance(value, list) else [value]
                for v in values:
                    if isinstance(v, str) and v not in valid_tags:
                        errors.append(
                            f"{prefix} condition[{j}]: tag value '{v}' not found in Trustin AML labels for parameter '{param}'"
                        )
    return errors


def main():
    rules_path = sys.argv[1] if len(sys.argv) > 1 else "rules.json"

    if not os.path.exists(rules_path):
        print(f"FAIL: Rules file not found: {rules_path}")
        sys.exit(1)

    if not os.path.exists(SCHEMA_PATH):
        print(f"FAIL: Schema file not found: {SCHEMA_PATH}")
        sys.exit(1)

    print(f"Validating: {rules_path}")
    print(f"Schema:     {SCHEMA_PATH}")
    print(f"Labels:     {LABELS_PATH}")
    print("-" * 50)

    try:
        rules = load_json(rules_path)
    except json.JSONDecodeError as e:
        print(f"FAIL: Invalid JSON - {e}")
        sys.exit(1)

    schema = load_json(SCHEMA_PATH)
    primary_cats, secondary_cats = parse_trustin_labels(LABELS_PATH)

    all_errors = []
    all_errors.extend(validate_schema_structure(rules, schema))
    all_errors.extend(validate_rule_id_uniqueness(rules))
    all_errors.extend(validate_tag_values(rules, primary_cats, secondary_cats))

    if all_errors:
        print(f"FAIL: {len(all_errors)} error(s) found:\n")
        for err in all_errors:
            print(f"  - {err}")
        sys.exit(1)
    else:
        print(f"PASS: {len(rules)} rule(s) validated successfully.")
        print(f"  - Schema structure: OK")
        print(f"  - Rule ID uniqueness: OK")
        if primary_cats:
            print(f"  - Tag values ({len(primary_cats)} primary, {len(secondary_cats)} secondary labels): OK")
        sys.exit(0)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)