220 lines
6.2 KiB
Go
220 lines
6.2 KiB
Go
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
|
|
}
|