use crate::nft::errors::{NftError, NftResult, RiskLevel};
use serde::{Deserialize, Serialize};
use solana_sdk::pubkey::Pubkey;
use std::collections::HashMap;
use std::fmt;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NftInfo {
pub id: Uuid,
pub mint_address: String,
pub token_account: String,
pub owner: String,
pub name: Option<String>,
pub symbol: Option<String>,
pub description: Option<String>,
pub metadata_uri: Option<String>,
pub image_uri: Option<String>,
pub animation_uri: Option<String>,
pub external_url: Option<String>,
pub collection: Option<CollectionInfo>,
pub creators: Vec<CreatorInfo>,
pub attributes: Vec<NftAttribute>,
pub token_standard: Option<String>,
pub master_edition: bool,
pub edition_number: Option<u64>,
pub max_supply: Option<u64>,
pub estimated_value_lamports: Option<u64>,
pub last_valuation: Option<chrono::DateTime<chrono::Utc>>,
pub security_assessment: SecurityAssessment,
pub rarity_score: Option<f64>,
pub quality_score: Option<f64>,
pub metadata_verified: bool,
pub image_verified: bool,
pub discovered_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub additional_metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CollectionInfo {
pub name: String,
pub symbol: Option<String>,
pub description: Option<String>,
pub image: Option<String>,
pub uri: Option<String>,
pub verified: bool,
pub collection_mint_address: Option<String>,
pub security_assessment: SecurityAssessment,
pub floor_price_lamports: Option<u64>,
pub total_supply: Option<u64>,
pub item_count: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreatorInfo {
pub address: String,
pub verified: bool,
pub share: u8,
pub name: Option<String>,
pub twitter: Option<String>,
pub website: Option<String>,
pub security_assessment: SecurityAssessment,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NftAttribute {
pub trait_type: String,
pub value: serde_json::Value,
pub rarity: Option<f64>,
pub rare: bool,
pub display_type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityAssessment {
pub risk_level: RiskLevel,
pub security_score: u8,
pub issues: Vec<SecurityIssue>,
pub verified: bool,
pub assessed_at: chrono::DateTime<chrono::Utc>,
pub confidence: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityIssue {
pub issue_type: SecurityIssueType,
pub severity: RiskLevel,
pub description: String,
pub recommendation: String,
pub confirmed: bool,
pub context: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SecurityIssueType {
SuspiciousMetadata,
MaliciousImage,
Phishing,
RugPullRisk,
Copymint,
Spam,
UnauthorizedCreator,
BrokenMetadata,
ExpiredDomain,
SuspiciousContract,
Honeypot,
Other { issue_type: String },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NftPortfolio {
pub id: Uuid,
pub wallet_address: String,
pub nfts: Vec<NftInfo>,
pub total_value_lamports: u64,
pub total_count: u32,
pub verified_count: u32,
pub high_risk_count: u32,
pub collection_breakdown: HashMap<String, CollectionBreakdown>,
pub value_distribution: ValueDistribution,
pub risk_distribution: RiskDistribution,
pub quality_metrics: PortfolioQualityMetrics,
pub analyzed_at: chrono::DateTime<chrono::Utc>,
pub analysis_duration_ms: u64,
pub analysis_config: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CollectionBreakdown {
pub collection_name: String,
pub count: u32,
pub total_value_lamports: u64,
pub average_value_lamports: u64,
pub portfolio_percentage: f64,
pub verified: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValueDistribution {
pub highest_value: Option<u64>,
pub lowest_value: Option<u64>,
pub median_value: Option<u64>,
pub average_value: f64,
pub percentiles: HashMap<u8, u64>,
pub concentration: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiskDistribution {
pub counts: HashMap<RiskLevel, u32>,
pub value_by_risk: HashMap<RiskLevel, u64>,
pub percentages: HashMap<RiskLevel, f64>,
pub overall_risk_score: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PortfolioQualityMetrics {
pub average_rarity_score: Option<f64>,
pub average_quality_score: Option<f64>,
pub verification_rate: f64,
pub metadata_completeness: f64,
pub image_availability: f64,
pub unique_collections: u32,
pub diversity_score: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NftScanConfig {
pub performance_mode: PerformanceMode,
pub max_concurrent_requests: usize,
pub request_timeout_ms: u64,
pub fetch_metadata: bool,
pub fetch_images: bool,
pub perform_security_validation: bool,
pub calculate_valuation: bool,
pub analyze_rarity: bool,
pub max_nfts_per_wallet: Option<u32>,
pub cache_config: CacheConfig,
pub security_config: SecurityConfig,
pub valuation_config: ValuationConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PerformanceMode {
UltraFast,
Fast,
Balanced,
Thorough,
Custom { settings: HashMap<String, serde_json::Value> },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CacheConfig {
pub enable_metadata_cache: bool,
pub enable_image_cache: bool,
pub enable_valuation_cache: bool,
pub cache_ttl_seconds: u64,
pub max_cache_size_mb: u64,
pub cleanup_interval_seconds: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
pub enable_validation: bool,
pub block_high_risk: bool,
pub block_unverified_collections: bool,
pub strict_mode: bool,
pub custom_rules: Vec<SecurityRule>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityRule {
pub name: String,
pub description: String,
pub condition: serde_json::Value,
pub action: SecurityAction,
pub priority: u8,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SecurityAction {
Allow,
Block,
Flag,
RequireValidation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValuationConfig {
pub enable_valuation: bool,
pub methods: Vec<ValuationMethod>,
pub floor_price_weight: f64,
pub recent_sales_weight: f64,
pub rarity_weight: f64,
pub max_sales_age_days: u32,
pub min_sales_count: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum ValuationMethod {
FloorPrice,
RecentSales,
RarityBased,
MlModel,
Custom { method_name: String, config: serde_json::Value },
}
impl Default for NftScanConfig {
fn default() -> Self {
Self {
performance_mode: PerformanceMode::Balanced,
max_concurrent_requests: 10,
request_timeout_ms: 30000,
fetch_metadata: true,
fetch_images: false,
perform_security_validation: true,
calculate_valuation: true,
analyze_rarity: true,
max_nfts_per_wallet: None,
cache_config: CacheConfig::default(),
security_config: SecurityConfig::default(),
valuation_config: ValuationConfig::default(),
}
}
}
impl Default for CacheConfig {
fn default() -> Self {
Self {
enable_metadata_cache: true,
enable_image_cache: false,
enable_valuation_cache: true,
cache_ttl_seconds: 300, max_cache_size_mb: 100,
cleanup_interval_seconds: 60,
}
}
}
impl Default for SecurityConfig {
fn default() -> Self {
Self {
enable_validation: true,
block_high_risk: false,
block_unverified_collections: false,
strict_mode: false,
custom_rules: vec![],
}
}
}
impl Default for ValuationConfig {
fn default() -> Self {
Self {
enable_valuation: true,
methods: vec![
ValuationMethod::FloorPrice,
ValuationMethod::RecentSales,
],
floor_price_weight: 0.4,
recent_sales_weight: 0.4,
rarity_weight: 0.2,
max_sales_age_days: 30,
min_sales_count: 3,
}
}
}
impl fmt::Display for PerformanceMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PerformanceMode::UltraFast => write!(f, "UltraFast"),
PerformanceMode::Fast => write!(f, "Fast"),
PerformanceMode::Balanced => write!(f, "Balanced"),
PerformanceMode::Thorough => write!(f, "Thorough"),
PerformanceMode::Custom { settings } => write!(f, "Custom({:?})", settings),
}
}
}
impl fmt::Display for SecurityIssueType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SecurityIssueType::SuspiciousMetadata => write!(f, "SuspiciousMetadata"),
SecurityIssueType::MaliciousImage => write!(f, "MaliciousImage"),
SecurityIssueType::Phishing => write!(f, "Phishing"),
SecurityIssueType::RugPullRisk => write!(f, "RugPullRisk"),
SecurityIssueType::Copymint => write!(f, "Copymint"),
SecurityIssueType::Spam => write!(f, "Spam"),
SecurityIssueType::UnauthorizedCreator => write!(f, "UnauthorizedCreator"),
SecurityIssueType::BrokenMetadata => write!(f, "BrokenMetadata"),
SecurityIssueType::ExpiredDomain => write!(f, "ExpiredDomain"),
SecurityIssueType::SuspiciousContract => write!(f, "SuspiciousContract"),
SecurityIssueType::Honeypot => write!(f, "Honeypot"),
SecurityIssueType::Other { issue_type } => write!(f, "Other({})", issue_type),
}
}
}
impl fmt::Display for SecurityAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SecurityAction::Allow => write!(f, "Allow"),
SecurityAction::Block => write!(f, "Block"),
SecurityAction::Flag => write!(f, "Flag"),
SecurityAction::RequireValidation => write!(f, "RequireValidation"),
}
}
}
impl fmt::Display for ValuationMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ValuationMethod::FloorPrice => write!(f, "FloorPrice"),
ValuationMethod::RecentSales => write!(f, "RecentSales"),
ValuationMethod::RarityBased => write!(f, "RarityBased"),
ValuationMethod::MlModel => write!(f, "MlModel"),
ValuationMethod::Custom { method_name, .. } => write!(f, "Custom({})", method_name),
}
}
}