package wallet import ( "ccoin/utils/crypto" "database/sql" "ccoin/models/wallet" "errors" "fmt" "time" ) type WalletService struct { db *sql.DB } // Creates a new instance of WalletService func NewWalletService(db *sql.DB) *WalletService { return &WalletService{db: db} } // Creates a new wallet with optional label func (ws *WalletService) CreateWallet(req wallet.CreateWalletRequest) (wallet.WalletResponse, error) { address := crypto.GenerateWalletAddress() timestamp := time.Now() var passwordHash string if req.Password != "" { passwordHash = crypto.HashPassword(req.Password) } else { return wallet.WalletResponse{}, fmt.Errorf("password field is required") } _, err := ws.db.Exec(` INSERT INTO wallets (address, balance, label, password_hash, created_at) VALUES ($1, $2, $3, $4, $5)`, address, 0.0, req.Label, passwordHash, timestamp.Unix(), ) if err != nil { return wallet.WalletResponse{}, err } return wallet.WalletResponse{ Address: address, Balance: 0.0, Label: req.Label, PasswordHash: passwordHash, CreatedAt: timestamp.Unix(), LastActivity: nil, }, nil } // Gets wallet by address func (ws *WalletService) GetWallet(address string) (*wallet.WalletResponse, error) { var w wallet.Wallet row := ws.db.QueryRow(` SELECT address, balance, label, password_hash, created_at, last_activity FROM wallets WHERE address = $1`, address) err := row.Scan(&w.Address, &w.Balance, &w.Label, &w.PasswordHash, &w.CreatedAt, &w.LastActivity) if err != nil { return nil, err } return &wallet.WalletResponse{ Address: w.Address, Balance: w.Balance, Label: w.Label, PasswordHash: w.PasswordHash, CreatedAt: w.CreatedAt.Unix(), LastActivity: ptrTime(w.LastActivity), }, nil } // Gets wallet balance func (ws *WalletService) GetWalletBalance(address string) (wallet.BalanceResponse, error) { var balance float64 err := ws.db.QueryRow(`SELECT balance FROM wallets WHERE address = $1`, address).Scan(&balance) if err != nil { return wallet.BalanceResponse{}, errors.New("wallet not found") } return wallet.BalanceResponse{ Address: address, Balance: balance, }, nil } // Updates wallet balance func (ws *WalletService) UpdateBalance(address string, amount float64) (bool, error) { _, err := ws.db.Exec(`UPDATE wallets SET balance = balance + $1, last_activity = $2 WHERE address = $3`, amount, time.Now().Unix(), address) if err != nil { return false, err } return true, nil } // Sets wallet balance to specific amount func (ws *WalletService) SetBalance(address string, amount float64) (bool, error) { _, err := ws.db.Exec(`UPDATE wallets SET balance = $1, last_activity = $2 WHERE address = $3`, amount, time.Now().Unix(), address) if err != nil { return false, err } return true, nil } // Updates wallet label func (ws *WalletService) UpdateLabel(address string, req wallet.UpdateWalletRequest) (bool, error) { result, err := ws.db.Exec(`UPDATE wallets SET label = $1 WHERE address = $2`, address, req.Label) if err != nil { return false, err } rowsAffected, _ := result.RowsAffected() return rowsAffected > 0, nil } // Checks if wallet exists func (ws *WalletService) WalletExists(address string) (bool, error) { var count int64 err := ws.db.QueryRow(`SELECT COUNT(*) FROM wallets WHERE address = $1`, address).Scan(&count) if err != nil { return false, err } return count > 0, nil } // Gets all wallets with pagination func (ws *WalletService) GetAllWallets(limit, offset int) ([]wallet.WalletResponse, error) { query := fmt.Sprintf(` SELECT address, balance, label, password_hash, created_at, last_activity FROM wallets ORDER BY created_at DESC LIMIT %d OFFSET %d`, limit, offset) rows, err := ws.db.Query(query) if err != nil { return nil, err } defer rows.Close() var wallets []wallet.WalletResponse for rows.Next() { var w wallet.Wallet if err := rows.Scan(&w.Address, &w.Balance, &w.Label, &w.PasswordHash, &w.CreatedAt, &w.LastActivity); err != nil { return nil, err } wallets = append(wallets, wallet.WalletResponse{ Address: w.Address, Balance: w.Balance, Label: w.Label, PasswordHash: w.PasswordHash, CreatedAt: w.CreatedAt.Unix(), LastActivity: ptrTime(w.LastActivity), }) } return wallets, nil } // Gets total number of wallets func (ws *WalletService) GetTotalWalletCount() (int64, error) { var count int64 err := ws.db.QueryRow(`SELECT COUNT(*) FROM wallets`).Scan(&count) if err != nil { return 0, err } return count, nil } // Gets wallet with balance greater than specified amount func (ws *WalletService) GetWalletsWithBalance(minBalance float64) ([]wallet.WalletResponse, error) { rows, err := ws.db.Query(`SELECT address, balance, label, password_hash, created_at, last_activity FROM wallets WHERE balance > $1 ORDER BY balance DESC`, minBalance) if err != nil { return nil, err } defer rows.Close() var wallets []wallet.WalletResponse for rows.Next() { var w wallet.Wallet if err := rows.Scan(&w.Address, &w.Balance, &w.Label, &w.PasswordHash, &w.CreatedAt, &w.LastActivity); err != nil { return nil, err } wallets = append(wallets, wallet.WalletResponse{ Address: w.Address, Balance: w.Balance, Label: w.Label, PasswordHash: w.PasswordHash, CreatedAt: w.CreatedAt.Unix(), LastActivity: ptrTime(w.LastActivity), }) } return wallets, nil } // Updates last activity timestamp func (ws *WalletService) UpdateLastActivity(address string) (bool, error) { _, err := ws.db.Exec(`UPDATE wallets SET last_activity = $1 WHERE address = $2`, time.Now().Unix(), address) if err != nil { return false, err } return true, nil } // Gets total supply across all wallets func (ws *WalletService) GetTotalSupply() (float64, error) { var totalSupply float64 err := ws.db.QueryRow(`SELECT SUM(balance) FROM wallets`).Scan(&totalSupply) if err != nil { return 0, err } return totalSupply, nil } // Helper function to convert *time.Time to *int64 for JSON response func ptrTime(t *time.Time) *int64 { if t == nil { return nil } unixTime := t.Unix() return &unixTime }