From abc8ee755394e16099bfb6f616428ecdf3c29763 Mon Sep 17 00:00:00 2001 From: darwincereska Date: Wed, 17 Dec 2025 10:25:50 -0500 Subject: [PATCH] feat: added wallet service --- .../org/ccoin/services/WalletService.kt | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/server/src/main/kotlin/org/ccoin/services/WalletService.kt b/server/src/main/kotlin/org/ccoin/services/WalletService.kt index e69de29..0cf303d 100644 --- a/server/src/main/kotlin/org/ccoin/services/WalletService.kt +++ b/server/src/main/kotlin/org/ccoin/services/WalletService.kt @@ -0,0 +1,138 @@ +package org.ccoin.services + +import org.ccoin.database.Tables +import org.ccoin.exceptions.WalletNotFoundException +import org.ccoin.models.WalletResponse +import org.ccoin.utils.CryptoUtils +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction +import java.math.BigDecimal +import java.time.Instant + +object WalletService { + + /** Creates a new wallet with optional label */ + fun createWallet(label: String? = null): WalletResponse { + val address = CryptoUtils.generateWalletAddress() + val timestamp = Instant.now().epochSecond + + return transaction { + Tables.Wallets.insert { + it[Tables.Wallets.address] = address + it[Tables.Wallets.label] = label + it[createdAt] = timestamp + } + + WalletResponse(address, 0.0, label, timestamp, null) + } + } + + /** Gets wallet by address */ + fun getWallet(address: String): WalletResponse? = transaction { + Tables.Wallets.selectAll().where { Tables.Wallets.address eq address } + .map { + WalletResponse( + it[Tables.Wallets.address], + it[Tables.Wallets.balance].toDouble(), + it[Tables.Wallets.label], + it[Tables.Wallets.createdAt], + it[Tables.Wallets.lastActivity] + ) + }.singleOrNull() + } + + /** Gets wallet balance */ + fun getWalletBalance(address: String): Double = transaction { + Tables.Wallets.selectAll().where { Tables.Wallets.address eq address } + .map { it[Tables.Wallets.balance].toDouble() } + .singleOrNull() ?: throw WalletNotFoundException(address) + } + + /** Updates wallet balance */ + fun updateBalance(address: String, amount: BigDecimal): Boolean = transaction { + val currentBalance = Tables.Wallets.selectAll() + .where { Tables.Wallets.address eq address } + .map { it[Tables.Wallets.balance] } + .singleOrNull() ?: return@transaction false + + val updated = Tables.Wallets.update({ Tables.Wallets.address eq address }) { + it[balance] = currentBalance.add(amount) + it[lastActivity] = Instant.now().epochSecond + } + updated > 0 + } + + /** Sets wallet balance to specific amount */ + fun setBalance(address: String, amount: BigDecimal): Boolean = transaction { + val updated = Tables.Wallets.update({ Tables.Wallets.address eq address }) { + it[balance] = amount + it[lastActivity] = Instant.now().epochSecond + } + updated > 0 + } + + /** Updates wallet label */ + fun updateLabel(address: String, label: String?): Boolean = transaction { + val updated = Tables.Wallets.update({ Tables.Wallets.address eq address }) { + it[Tables.Wallets.label] = label + } + updated > 0 + } + + /** Checks if wallet exists */ + fun walletExists(address: String): Boolean = transaction { + Tables.Wallets.selectAll().where { Tables.Wallets.address eq address }.count() > 0 + } + + /** Gets all wallets with pagination */ + fun getAllWallets(limit: Int = 50, offset: Int = 0): List = transaction { + Tables.Wallets.selectAll() + .orderBy(Tables.Wallets.createdAt, SortOrder.DESC) + .limit(limit) + .offset(offset.toLong()) + .map { + WalletResponse( + it[Tables.Wallets.address], + it[Tables.Wallets.balance].toDouble(), + it[Tables.Wallets.label], + it[Tables.Wallets.createdAt], + it[Tables.Wallets.lastActivity] + ) + } + } + + /** Gets total number of wallets */ + fun getTotalWalletCount(): Long = transaction { + Tables.Wallets.selectAll().count() + } + + /** Gets wallets with balance greater than specified amount */ + fun getWalletsWithBalance(minBalance: Double): List = transaction { + Tables.Wallets.selectAll().where { Tables.Wallets.balance greater BigDecimal.valueOf(minBalance) } + .orderBy(Tables.Wallets.balance, SortOrder.DESC) + .map { + WalletResponse( + it[Tables.Wallets.address], + it[Tables.Wallets.balance].toDouble(), + it[Tables.Wallets.label], + it[Tables.Wallets.createdAt], + it[Tables.Wallets.lastActivity] + ) + } + } + + /** Updates last activity timestamp */ + fun updateLastActivity(address: String): Boolean = transaction { + val updated = Tables.Wallets.update({ Tables.Wallets.address eq address }) { + it[lastActivity] = Instant.now().epochSecond + } + updated > 0 + } + + /** Gets total supply across all wallets */ + fun getTotalSupply(): Double = transaction { + Tables.Wallets.select(Tables.Wallets.balance.sum()) + .single()[Tables.Wallets.balance.sum()]?.toDouble() ?: 0.0 + } +} +