circle_compliance/models/
screening.rs1#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
5#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
6pub enum Chain {
7 Eth,
9 #[serde(rename = "ETH-SEPOLIA")]
11 EthSepolia,
12 Avax,
14 #[serde(rename = "AVAX-FUJI")]
16 AvaxFuji,
17 Matic,
19 #[serde(rename = "MATIC-AMOY")]
21 MaticAmoy,
22 Algo,
24 Atom,
26 Arb,
28 #[serde(rename = "ARB-SEPOLIA")]
30 ArbSepolia,
31 Hbar,
33 Sol,
35 #[serde(rename = "SOL-DEVNET")]
37 SolDevnet,
38 Uni,
40 #[serde(rename = "UNI-SEPOLIA")]
42 UniSepolia,
43 Trx,
45 Xlm,
47 Bch,
49 Btc,
51 Bsv,
53 Etc,
55 Ltc,
57 Xmr,
59 Xrp,
61 Zrx,
63 Op,
65 Dot,
67}
68
69#[derive(Debug, Clone, serde::Serialize)]
71#[serde(rename_all = "camelCase")]
72pub struct ScreenAddressRequest {
73 pub idempotency_key: String,
75 pub address: String,
77 pub chain: Chain,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
83#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
84pub enum RiskAction {
85 Approve,
87 Review,
89 FreezeWallet,
91 Deny,
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
97#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
98pub enum RiskScore {
99 Unknown,
101 Low,
103 Medium,
105 High,
107 Severe,
109 Blocklist,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
115#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
116pub enum RiskCategory {
117 Sanctions,
119 Csam,
121 IllicitBehavior,
123 Gambling,
125 TerroristFinancing,
127 Unsupported,
129 Frozen,
131 Other,
133 HighRiskIndustry,
135 Pep,
137 Trusted,
139 Hacking,
141 HumanTrafficking,
143 SpecialMeasures,
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
149#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
150pub enum RiskType {
151 Ownership,
153 Counterparty,
155 Indirect,
157}
158
159#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
161#[serde(rename_all = "camelCase")]
162pub struct SignalSource {
163 pub row_id: String,
165 pub pointer: String,
167}
168
169#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
171#[serde(rename_all = "camelCase")]
172pub struct RiskSignal {
173 pub source: String,
175 pub source_value: String,
177 pub risk_score: RiskScore,
179 pub risk_categories: Vec<RiskCategory>,
181 #[serde(rename = "type")]
183 pub risk_type: RiskType,
184 pub signal_source: Option<SignalSource>,
186}
187
188#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
190#[serde(rename_all = "camelCase")]
191pub struct AddressScreeningDecision {
192 pub screening_date: String,
194 pub rule_name: Option<String>,
196 pub actions: Option<Vec<RiskAction>>,
198 pub reasons: Option<Vec<RiskSignal>>,
200}
201
202#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct ScreeningVendorDetail {
206 pub id: String,
208 pub vendor: String,
210 pub response: serde_json::Value,
212 pub create_date: String,
214}
215
216#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
221pub struct ScreenAddressEnvelope {
222 pub data: BlockchainAddressScreeningResponse,
224}
225
226#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
228#[serde(rename_all = "camelCase")]
229pub struct BlockchainAddressScreeningResponse {
230 pub result: ScreeningResult,
232 pub decision: AddressScreeningDecision,
234 pub id: String,
236 pub address: String,
238 pub chain: Chain,
240 pub details: Vec<ScreeningVendorDetail>,
242 pub alert_id: Option<String>,
244}
245
246#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
248#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
249pub enum ScreeningResult {
250 Approved,
252 Denied,
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259
260 #[test]
261 fn chain_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
262 let s = serde_json::to_string(&Chain::EthSepolia)?;
263 assert_eq!(s, "\"ETH-SEPOLIA\"");
264 let parsed: Chain = serde_json::from_str("\"MATIC\"")?;
265 assert_eq!(parsed, Chain::Matic);
266 Ok(())
267 }
268
269 #[test]
270 fn risk_action_deserializes() -> Result<(), Box<dyn std::error::Error>> {
271 let a: RiskAction = serde_json::from_str("\"APPROVE\"")?;
272 assert_eq!(a, RiskAction::Approve);
273 Ok(())
274 }
275}