From 3c097af03d6d4d5acfe7880a11f349b0eec088dc Mon Sep 17 00:00:00 2001 From: darwincereska Date: Thu, 18 Dec 2025 09:37:43 -0500 Subject: [PATCH] feat: added transaction routes --- .../org/ccoin/routes/TransactionRoutes.kt | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/server/src/main/kotlin/org/ccoin/routes/TransactionRoutes.kt b/server/src/main/kotlin/org/ccoin/routes/TransactionRoutes.kt index e69de29..2b17c84 100644 --- a/server/src/main/kotlin/org/ccoin/routes/TransactionRoutes.kt +++ b/server/src/main/kotlin/org/ccoin/routes/TransactionRoutes.kt @@ -0,0 +1,210 @@ +package org.ccoin.routes + +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import org.ccoin.models.SendTransactionRequest +import org.ccoin.services.TransactionService +import org.ccoin.services.ValidationService + +fun Route.transactionRoutes() { + route("/transaction") { + /** Send a transaction */ + post("/send") { + try { + val request = call.receive() + + // Validate transaction data + val validation = ValidationService.validateTransaction( + request.fromAddress, + request.toAddress, + request.amount, + request.fee, + request.memo + ) + + if (!validation.isValid) { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to validation.getErrorMessage())) + return@post + } + + val transaction = TransactionService.sendTransaction( + request.fromAddress, + request.toAddress, + request.amount, + request.fee, + request.memo + ) + + call.respond(HttpStatusCode.Created, transaction) + + } catch (e: Exception) { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to (e.message ?: "Transaction failed"))) + } + } + + /** Get transaction by hash */ + get("/{hash}") { + try { + val hash = call.parameters["hash"] ?: run { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Transaction hash parameter required")) + return@get + } + + // Validate hash format + if (!ValidationService.validateTransactionHash(hash)) { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid transaction hash format")) + return@get + } + + val transaction = TransactionService.getTransaction(hash) + if (transaction != null) { + call.respond(transaction) + } else { + call.respond(HttpStatusCode.NotFound, mapOf("error" to "Transaction not found")) + } + + } catch (e: Exception) { + call.respond(HttpStatusCode.InternalServerError, mapOf("error" to (e.message ?: "Failed to get transaction"))) + } + } + + /** Get transaction history for an address */ + get("/history/{address}") { + try { + val address = call.parameters["address"] ?: run { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Address parameter required")) + return@get + } + + val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1 + val pageSize = call.request.queryParameters["pageSize"]?.toIntOrNull() ?: 50 + + // Validate address format + if (!ValidationService.validateWalletAddress(address)) { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid address format")) + return@get + } + + // Validate pagination + val validation = ValidationService.validatePagination(page, pageSize) + if (!validation.isValid) { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to validation.getErrorMessage())) + return@get + } + + val offset = (page - 1) * pageSize + val transactions = TransactionService.getTransactionHistory(address, pageSize, offset) + val totalCount = TransactionService.getTransactionCountForAddress(address) + + call.respond(mapOf( + "transactions" to transactions, + "address" to address, + "pagination" to mapOf( + "currentPage" to page, + "pageSize" to pageSize, + "totalItems" to totalCount, + "totalPages" to ((totalCount + pageSize - 1) / pageSize), + "hasNext" to (offset + pageSize < totalCount), + "hasPrevious" to (page > 1) + ) + )) + + } catch (e: Exception) { + call.respond(HttpStatusCode.InternalServerError, mapOf("error" to (e.message ?: "Failed to get transaction history"))) + } + } + + /** Get pending transactions */ + get("/pending") { + try { + val transactions = TransactionService.getPendingTransactions() + call.respond(mapOf( + "transactions" to transactions, + "count" to transactions.size + )) + + } catch (e: Exception) { + call.respond(HttpStatusCode.InternalServerError, mapOf("error" to (e.message ?: "Failed to get pending transactions"))) + } + } + + /** Get transaction count for address */ + get("/count/{address}") { + try { + val address = call.parameters["address"] ?: run { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Address parameter required")) + return@get + } + + // Validate address format + if (!ValidationService.validateWalletAddress(address)) { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid address format")) + return@get + } + + val count = TransactionService.getTransactionCountForAddress(address) + call.respond(mapOf( + "address" to address, + "transactionCount" to count + )) + + } catch (e: Exception) { + call.respond(HttpStatusCode.InternalServerError, mapOf("error" to (e.message ?: "Failed to get transaction count"))) + } + } + + /** Get all transactions with pagination */ + get("/list") { + try { + val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1 + val pageSize = call.request.queryParameters["pageSize"]?.toIntOrNull() ?: 50 + val status = call.request.queryParameters["status"] // Optional filter + + // Validate pagination + val validation = ValidationService.validatePagination(page, pageSize) + if (!validation.isValid) { + call.respond(HttpStatusCode.BadRequest, mapOf("error" to validation.getErrorMessage())) + return@get + } + + // For now, just get pending transactions as an example + // You could extend this to support status filtering + val transactions = if (status == "pending") { + TransactionService.getPendingTransactions() + } else { + // This would need a new service method for all transactions + TransactionService.getPendingTransactions() // Placeholder + } + + call.respond(mapOf( + "transactions" to transactions, + "count" to transactions.size, + "status" to status + )) + + } catch (e: Exception) { + call.respond(HttpStatusCode.InternalServerError, mapOf("error" to (e.message ?: "Failed to get transactions"))) + } + } + + /** Get network transaction statistics */ + get("/stats") { + try { + val totalCount = TransactionService.getTotalTransactionCount() + val pendingCount = TransactionService.getPendingTransactions().size + + call.respond(mapOf( + "totalTransactions" to totalCount, + "pendingTransactions" to pendingCount, + "confirmedTransactions" to (totalCount - pendingCount) + )) + + } catch (e: Exception) { + call.respond(HttpStatusCode.InternalServerError, mapOf("error" to (e.message ?: "Failed to get transaction statistics"))) + } + } + } +}