// Package ante — 验证节点级合规交易拦截 // // ComplianceAnteHandler 在验证节点打包交易前执行合规检查: // 1. OFAC 地址拦截 — 制裁名单地址的交易直接拒绝 // 2. Structuring 检测 — 拆分交易规避 $3,000 Travel Rule 阈值 // 3. Travel Rule 预检查 — ≥$3,000 转移必须携带身份哈希 // // 参考: FinCEN Travel Rule, OFAC SDN List, FATF Recommendation 16 package ante import ( "fmt" "math/big" "sync" "time" ) // ComplianceAnteHandler 验证节点级合规检查处理器 type ComplianceAnteHandler struct { mu sync.RWMutex // OFAC 制裁名单(地址 → 是否制裁) ofacList map[string]bool // Travel Rule 记录(sender+receiver hash → 是否已记录) travelRuleRecords map[string]bool // Structuring 检测:地址 → 24h 内累计转移金额 recentTransfers map[string]*TransferWindow // 配置 travelRuleThreshold *big.Int // $3,000 USDC (3000 * 1e6) structuringWindow time.Duration } // TransferWindow 滑动窗口内的转移记录 type TransferWindow struct { TotalAmount *big.Int Transfers []TransferRecord } // TransferRecord 单笔转移记录 type TransferRecord struct { Amount *big.Int Timestamp time.Time } // ComplianceResult 合规检查结果 type ComplianceResult struct { Allowed bool Reason string Suspicious bool // 标记为可疑但不拒绝 SuspReason string // 可疑原因 } // NewComplianceAnteHandler 创建合规检查处理器 func NewComplianceAnteHandler() *ComplianceAnteHandler { threshold := new(big.Int).Mul(big.NewInt(3000), big.NewInt(1e6)) // $3,000 USDC return &ComplianceAnteHandler{ ofacList: make(map[string]bool), travelRuleRecords: make(map[string]bool), recentTransfers: make(map[string]*TransferWindow), travelRuleThreshold: threshold, structuringWindow: 24 * time.Hour, } } // AnteHandle 执行合规检查(在交易打包前调用) // // 返回: // - ComplianceResult.Allowed = false: 交易被拒绝,不会被打包 // - ComplianceResult.Suspicious = true: 标记为可疑,仍可打包但上报 func (h *ComplianceAnteHandler) AnteHandle(from, to string, value *big.Int) ComplianceResult { h.mu.RLock() defer h.mu.RUnlock() // 1. OFAC 地址拦截(链级强制) if h.ofacList[from] { return ComplianceResult{ Allowed: false, Reason: fmt.Sprintf("OFAC sanctioned address (sender: %s), transaction rejected at validator level", from), } } if h.ofacList[to] { return ComplianceResult{ Allowed: false, Reason: fmt.Sprintf("OFAC sanctioned address (receiver: %s), transaction rejected at validator level", to), } } result := ComplianceResult{Allowed: true} // 2. Structuring 检测(拆分交易规避 $3,000 阈值) if h.isStructuringPattern(from, value) { result.Suspicious = true result.SuspReason = fmt.Sprintf( "Potential structuring detected for %s: cumulative transfers approaching Travel Rule threshold", from, ) } // 3. Travel Rule 预打包检查(≥$3,000) if value.Cmp(h.travelRuleThreshold) >= 0 { recordKey := fmt.Sprintf("%s:%s", from, to) if !h.travelRuleRecords[recordKey] { return ComplianceResult{ Allowed: false, Reason: fmt.Sprintf("Travel Rule: identity data required for transfers >= $3,000 (from: %s, to: %s)", from, to), } } } return result } // isStructuringPattern 检测是否存在拆分交易模式 // 规则:24h 内同一地址的累计小额转移接近或超过 $3,000 func (h *ComplianceAnteHandler) isStructuringPattern(from string, currentValue *big.Int) bool { window, exists := h.recentTransfers[from] if !exists { return false } // 清理过期记录 now := time.Now() var validTransfers []TransferRecord totalAmount := new(big.Int) for _, t := range window.Transfers { if now.Sub(t.Timestamp) <= h.structuringWindow { validTransfers = append(validTransfers, t) totalAmount.Add(totalAmount, t.Amount) } } // 加上当前交易 totalAmount.Add(totalAmount, currentValue) // 如果每笔都低于阈值,但累计超过阈值 → 可疑 allBelowThreshold := true for _, t := range validTransfers { if t.Amount.Cmp(h.travelRuleThreshold) >= 0 { allBelowThreshold = false break } } if currentValue.Cmp(h.travelRuleThreshold) >= 0 { allBelowThreshold = false } return allBelowThreshold && totalAmount.Cmp(h.travelRuleThreshold) >= 0 } // ======================== // OFAC 名单管理 // ======================== // UpdateOFACList 更新 OFAC 制裁名单(由链下服务定期调用) func (h *ComplianceAnteHandler) UpdateOFACList(addresses []string) { h.mu.Lock() defer h.mu.Unlock() h.ofacList = make(map[string]bool, len(addresses)) for _, addr := range addresses { h.ofacList[addr] = true } } // AddToOFACList 添加地址到 OFAC 名单 func (h *ComplianceAnteHandler) AddToOFACList(address string) { h.mu.Lock() defer h.mu.Unlock() h.ofacList[address] = true } // RemoveFromOFACList 从 OFAC 名单移除 func (h *ComplianceAnteHandler) RemoveFromOFACList(address string) { h.mu.Lock() defer h.mu.Unlock() delete(h.ofacList, address) } // IsOFACSanctioned 查询地址是否在 OFAC 名单中 func (h *ComplianceAnteHandler) IsOFACSanctioned(address string) bool { h.mu.RLock() defer h.mu.RUnlock() return h.ofacList[address] } // ======================== // Travel Rule 管理 // ======================== // RecordTravelRule 记录 Travel Rule 数据 func (h *ComplianceAnteHandler) RecordTravelRule(from, to string) { h.mu.Lock() defer h.mu.Unlock() key := fmt.Sprintf("%s:%s", from, to) h.travelRuleRecords[key] = true } // HasTravelRuleRecord 查询是否已记录 Travel Rule func (h *ComplianceAnteHandler) HasTravelRuleRecord(from, to string) bool { h.mu.RLock() defer h.mu.RUnlock() key := fmt.Sprintf("%s:%s", from, to) return h.travelRuleRecords[key] } // ======================== // 转移记录(Structuring 检测用) // ======================== // RecordTransfer 记录一笔转移(用于 Structuring 检测) func (h *ComplianceAnteHandler) RecordTransfer(from string, amount *big.Int) { h.mu.Lock() defer h.mu.Unlock() window, exists := h.recentTransfers[from] if !exists { window = &TransferWindow{ TotalAmount: new(big.Int), Transfers: make([]TransferRecord, 0), } h.recentTransfers[from] = window } window.Transfers = append(window.Transfers, TransferRecord{ Amount: new(big.Int).Set(amount), Timestamp: time.Now(), }) window.TotalAmount.Add(window.TotalAmount, amount) } // GetOFACListSize 获取当前 OFAC 名单大小 func (h *ComplianceAnteHandler) GetOFACListSize() int { h.mu.RLock() defer h.mu.RUnlock() return len(h.ofacList) }