feat: added wallet service

This commit is contained in:
darwincereska
2025-12-23 17:38:27 -05:00
parent 23f6dba3f3
commit 99c5dba721
9 changed files with 527 additions and 5 deletions

View File

@@ -0,0 +1,219 @@
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
}