From 0a953eecf004a3df4146eb7a5779cbd699292f46 Mon Sep 17 00:00:00 2001 From: Fatemeh imani <46007372+fatemeh-i@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:29:06 +0330 Subject: [PATCH 1/9] Develop new services to fetch user's transaction history (#451) * change tx history query to have better performance * update trx security filter * fix reference of currencies comparation ( object -> symbol) * seprate withdraw categories based on steps, enable unlimited report history * add withdraw filed to tx history resp * fix withdraw settelment filed to tx history resp * expose chains information service * change permission of getChainsInfo * fix query syntax * start developing new service to fetch tx history * fetch tx of trades table to have new tx history service * Save deposit tx seprately * develop new service to fetch deposit history --- .../co/nilin/opex/api/core/spi/WalletProxy.kt | 31 +- .../binance/controller/WalletController.kt | 279 +++++++++--------- .../ports/proxy/data/TransactionRequest.kt | 11 +- .../api/ports/proxy/impl/WalletProxyImpl.kt | 112 +++---- .../opex/bcgateway/core/model/Deposit.kt | 18 +- .../core/service/WalletSyncServiceImpl.kt | 2 +- .../opex/bcgateway/core/spi/DepositHandler.kt | 2 + .../opex/bcgateway/core/spi/WalletProxy.kt | 2 +- .../ports/postgres/impl/DepositHandlerImpl.kt | 8 +- .../ports/postgres/model/DepositModel.kt | 3 +- .../src/main/resources/schema.sql | 3 + .../ports/walletproxy/impl/WalletProxyImpl.kt | 4 +- .../app/controller/MarketStatsController.kt | 7 +- .../app/controller/UserDataController.kt | 18 +- .../opex/market/core/inout/Transaction.kt | 17 ++ .../market/core/inout/TransactionRequest.kt | 12 + .../market/core/spi/MarketQueryHandler.kt | 12 +- .../opex/market/core/spi/UserQueryHandler.kt | 4 + .../ports/postgres/dao/TradeRepository.kt | 130 +++++--- .../postgres/impl/MarketQueryHandlerImpl.kt | 181 ++++++------ .../postgres/impl/UserQueryHandlerImpl.kt | 94 +++--- .../opex/wallet/app/config/SecurityConfig.kt | 2 + .../app/controller/DepositController.kt | 86 ++++++ .../app/controller/TransactionController.kt | 3 +- .../app/controller/TransferController.kt | 32 +- .../app/controller/WithdrawController.kt | 152 +++++----- .../wallet/app/service/TransferService.kt | 57 +++- .../nilin/opex/wallet/core/inout/Deposit.kt | 25 ++ .../wallet/core/inout/WithdrawResponse.kt | 3 +- .../wallet/core/service/WithdrawService.kt | 6 +- .../opex/wallet/core/spi/DepositPersister.kt | 27 ++ .../wallet/core/spi/TransactionManager.kt | 3 +- .../opex/wallet/core/spi/WithdrawPersister.kt | 5 +- .../ports/postgres/dao/DepositRepository.kt | 58 ++++ .../ports/postgres/dao/WithdrawRepository.kt | 113 ++++--- .../postgres/impl/DepositPersisterImpl.kt | 53 ++++ .../postgres/impl/TransactionManagerImpl.kt | 187 ++++++------ .../postgres/impl/WithdrawPersisterImpl.kt | 253 ++++++++-------- .../ports/postgres/model/DepositModel.kt | 25 ++ .../wallet/ports/postgres/util/Convertor.kt | 44 +++ .../src/main/resources/schema.sql | 21 +- 41 files changed, 1325 insertions(+), 780 deletions(-) create mode 100644 market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt create mode 100644 market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionRequest.kt create mode 100644 wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt create mode 100644 wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt create mode 100644 wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/DepositPersister.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/DepositRepository.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/DepositPersisterImpl.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/DepositModel.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index b93517a00..85a628217 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -14,23 +14,26 @@ interface WalletProxy { suspend fun getOwnerLimits(uuid: String?, token: String?): OwnerLimitsResponse suspend fun getDepositTransactions( - uuid: String, - token: String?, - coin: String?, - startTime: Long, - endTime: Long, - limit: Int, - offset: Int + uuid: String, + token: String?, + coin: String?, + startTime: Long?, + endTime: Long?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? ): List suspend fun getWithdrawTransactions( - uuid: String, - token: String?, - coin: String?, - startTime: Long, - endTime: Long, - limit: Int, - offset: Int + uuid: String, + token: String?, + coin: String?, + startTime: Long?, + endTime: Long?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? ): List + } \ No newline at end of file diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt index 1b009660f..2209814a0 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt @@ -21,24 +21,24 @@ import java.util.* @RestController class WalletController( - private val walletProxy: WalletProxy, - private val symbolMapper: SymbolMapper, - private val marketDataProxy: MarketDataProxy, - private val accountantProxy: AccountantProxy, - private val bcGatewayProxy: BlockchainGatewayProxy, + private val walletProxy: WalletProxy, + private val symbolMapper: SymbolMapper, + private val marketDataProxy: MarketDataProxy, + private val accountantProxy: AccountantProxy, + private val bcGatewayProxy: BlockchainGatewayProxy, ) { @GetMapping("/v1/capital/deposit/address") suspend fun assignAddress( - @RequestParam - coin: String, - @RequestParam - network: String, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long, - @CurrentSecurityContext securityContext: SecurityContext + @RequestParam + coin: String, + @RequestParam + network: String, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long, + @CurrentSecurityContext securityContext: SecurityContext ): AssignAddressResponse { val response = bcGatewayProxy.assignAddress(securityContext.jwtAuthentication().name, coin, network) val address = response?.addresses @@ -48,36 +48,37 @@ class WalletController( @GetMapping("/v1/capital/deposit/hisrec") suspend fun getDepositTransactions( - @RequestParam(required = false) - coin: String?, - @RequestParam("network", required = false) - status: Int?, - @RequestParam(required = false) - startTime: Long?, - - @RequestParam(required = false) - endTime: Long?, - @RequestParam(required = false) - offset: Int?, - @RequestParam(required = false) - limit: Int?, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long, - @CurrentSecurityContext securityContext: SecurityContext + @RequestParam(required = false) + coin: String?, + @RequestParam("network", required = false) + status: Int?, + @RequestParam(required = false) + startTime: Long?, + @RequestParam(required = false) + endTime: Long?, + @RequestParam(required = false) + offset: Int?, + @RequestParam(required = false) + limit: Int?, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long, + @RequestParam(required = false) + ascendingByTime: Boolean? = false, + @CurrentSecurityContext securityContext: SecurityContext ): List { val validLimit = limit ?: 1000 val deposits = walletProxy.getDepositTransactions( - securityContext.jwtAuthentication().name, - securityContext.jwtAuthentication().tokenValue(), - coin, - startTime ?: Interval.ThreeMonth.getDate().time, - endTime ?: Date().time, - if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, - offset ?: 0 + securityContext.jwtAuthentication().name, + securityContext.jwtAuthentication().tokenValue(), + coin, + startTime ?: null, + endTime ?: Date().time, + if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, + offset ?: 0, + ascendingByTime ) - if (deposits.isEmpty()) return emptyList() @@ -87,35 +88,38 @@ class WalletController( @GetMapping("/v1/capital/withdraw/history") suspend fun getWithdrawTransactions( - @RequestParam(required = false) - coin: String, - @RequestParam(required = false) - withdrawOrderId: String?, - @RequestParam("status", required = false) - withdrawStatus: Int?, - @RequestParam(required = false) - offset: Int?, - @RequestParam(required = false) - limit: Int?, - @RequestParam(required = false) - startTime: Long?, - @RequestParam(required = false) - endTime: Long?, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long, - @CurrentSecurityContext securityContext: SecurityContext + @RequestParam(required = false) + coin: String, + @RequestParam(required = false) + withdrawOrderId: String?, + @RequestParam("status", required = false) + withdrawStatus: Int?, + @RequestParam(required = false) + offset: Int?, + @RequestParam(required = false) + limit: Int?, + @RequestParam(required = false) + startTime: Long?, + @RequestParam(required = false) + endTime: Long?, + @RequestParam(required = false) + ascendingByTime: Boolean? = false, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long, + @CurrentSecurityContext securityContext: SecurityContext ): List { val validLimit = limit ?: 1000 val response = walletProxy.getWithdrawTransactions( - securityContext.jwtAuthentication().name, - securityContext.jwtAuthentication().tokenValue(), - coin, - startTime ?: Interval.ThreeMonth.getDate().time, - endTime ?: Date().time, - if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, - offset ?: 0 + securityContext.jwtAuthentication().name, + securityContext.jwtAuthentication().tokenValue(), + coin, + startTime ?: null, + endTime ?: null, + if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, + offset ?: 0, + ascendingByTime ) return response.map { val status = when (it.status) { @@ -126,33 +130,34 @@ class WalletController( } WithdrawResponse( - it.destAddress ?: "0x0", - it.amount, - LocalDateTime.ofInstant(Instant.ofEpochMilli(it.createDate), ZoneId.systemDefault()) - .toString() - .replace("T", " "), - it.destSymbol ?: "", - it.withdrawId?.toString() ?: "", - "", - it.destNetwork ?: "", - 1, - status, - it.appliedFee.toString(), - 3, - it.destTransactionRef ?: it.withdrawId.toString(), - if (status == 1 && it.acceptDate != null) it.acceptDate!! else it.createDate + it.destAddress ?: "0x0", + it.amount, + LocalDateTime.ofInstant(Instant.ofEpochMilli(it.createDate), ZoneId.systemDefault()) + .toString() + .replace("T", " "), + it.destSymbol ?: "", + it.withdrawId?.toString() ?: "", + "", + it.destNetwork ?: "", + 1, + status, + it.appliedFee.toString(), + 3, + it.destTransactionRef ?: it.withdrawId.toString(), + if (status == 1 && it.acceptDate != null) it.acceptDate!! else it.createDate ) } } + @GetMapping("/v1/asset/tradeFee") suspend fun getPairFees( - @RequestParam(required = false) - symbol: String?, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long + @RequestParam(required = false) + symbol: String?, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long ): List { return if (symbol != null) { val internalSymbol = symbolMapper.toInternalSymbol(symbol) ?: throw OpexError.SymbolNotFound.exception() @@ -160,35 +165,35 @@ class WalletController( val fee = accountantProxy.getFeeConfig(internalSymbol) arrayListOf().apply { add( - PairFeeResponse( - symbol, - fee.makerFee.toDouble(), - fee.takerFee.toDouble() - ) + PairFeeResponse( + symbol, + fee.makerFee.toDouble(), + fee.takerFee.toDouble() + ) ) } } else accountantProxy.getFeeConfigs() - .distinctBy { it.pair } - .map { - PairFeeResponse( - symbolMapper.fromInternalSymbol(it.pair) ?: it.pair, - it.makerFee.toDouble(), - it.takerFee.toDouble() - ) - } + .distinctBy { it.pair } + .map { + PairFeeResponse( + symbolMapper.fromInternalSymbol(it.pair) ?: it.pair, + it.makerFee.toDouble(), + it.takerFee.toDouble() + ) + } } @GetMapping("/v1/asset/getUserAsset") suspend fun getUserAssets( - @CurrentSecurityContext - securityContext: SecurityContext, - @RequestParam(required = false) - symbol: String?, - @RequestParam(required = false) - quoteAsset: String?, - @RequestParam(required = false) - calculateEvaluation: Boolean? + @CurrentSecurityContext + securityContext: SecurityContext, + @RequestParam(required = false) + symbol: String?, + @RequestParam(required = false) + quoteAsset: String?, + @RequestParam(required = false) + calculateEvaluation: Boolean? ): List { val auth = securityContext.jwtAuthentication() val result = arrayListOf() @@ -198,8 +203,8 @@ class WalletController( result.add(AssetResponse(wallet.asset, wallet.balance, wallet.locked, wallet.withdraw)) } else { result.addAll( - walletProxy.getWallets(auth.name, auth.tokenValue()) - .map { AssetResponse(it.asset, it.balance, it.locked, it.withdraw) } + walletProxy.getWallets(auth.name, auth.tokenValue()) + .map { AssetResponse(it.asset, it.balance, it.locked, it.withdraw) } ) } @@ -207,11 +212,11 @@ class WalletController( return result val prices = marketDataProxy.getBestPriceForSymbols( - result.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } + result.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } ).associateBy { it.symbol.split("_")[0] } result.associateWith { prices[it.asset] } - .forEach { (asset, price) -> asset.valuation = price?.bidPrice ?: BigDecimal.ZERO } + .forEach { (asset, price) -> asset.valuation = price?.bidPrice ?: BigDecimal.ZERO } if (calculateEvaluation == true) result.forEach { @@ -225,32 +230,32 @@ class WalletController( @GetMapping("/v1/asset/estimatedValue") suspend fun assetsEstimatedValue( - @CurrentSecurityContext - securityContext: SecurityContext, - @RequestParam - quoteAsset: String + @CurrentSecurityContext + securityContext: SecurityContext, + @RequestParam + quoteAsset: String ): AssetsEstimatedValue { val auth = securityContext.jwtAuthentication() val wallets = walletProxy.getWallets(auth.name, auth.tokenValue()) val rates = marketDataProxy.getBestPriceForSymbols( - wallets.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } + wallets.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } ).associateBy { it.symbol.split("_")[0] } var value = BigDecimal.ZERO val zeroAssets = arrayListOf() wallets.associateWith { rates[it.asset] } - .forEach { (asset, price) -> - if (price == null || (price.bidPrice ?: BigDecimal.ZERO) == BigDecimal.ZERO) - zeroAssets.add(asset.asset) - else - value += asset.balance.multiply(price.bidPrice) - } + .forEach { (asset, price) -> + if (price == null || (price.bidPrice ?: BigDecimal.ZERO) == BigDecimal.ZERO) + zeroAssets.add(asset.asset) + else + value += asset.balance.multiply(price.bidPrice) + } return AssetsEstimatedValue(value, quoteAsset.uppercase(), zeroAssets) } private fun matchDepositsAndDetails( - deposits: List, - details: List + deposits: List, + details: List ): List { val detailMap = details.associateBy { it.hash } return deposits.associateWith { @@ -258,18 +263,18 @@ class WalletController( }.mapNotNull { (deposit, detail) -> detail?.let { DepositResponse( - deposit.amount, - deposit.currency, - detail.chain, - 1, - detail.address, - null, - deposit.ref ?: deposit.id.toString(), - deposit.date, - 1, - "1/1", - "1/1", - deposit.date + deposit.amount, + deposit.currency, + detail.chain, + 1, + detail.address, + null, + deposit.ref ?: deposit.id.toString(), + deposit.date, + 1, + "1/1", + "1/1", + deposit.date ) } } diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/TransactionRequest.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/TransactionRequest.kt index f3b61e984..33a6640f4 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/TransactionRequest.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/TransactionRequest.kt @@ -1,9 +1,10 @@ package co.nilin.opex.api.ports.proxy.data data class TransactionRequest( - val coin: String?, - val startTime: Long, - val endTime: Long, - val limit: Int, - val offset: Int + val coin: String?, + val startTime: Long?=null, + val endTime: Long?=null, + val limit: Int, + val offset: Int, + val ascendingByTime: Boolean? = false ) \ No newline at end of file diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index d5ee7d93d..adb824780 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -30,81 +30,85 @@ class WalletProxyImpl(private val webClient: WebClient) : WalletProxy { override suspend fun getWallets(uuid: String?, token: String?): List { logger.info("fetching wallets for $uuid") return webClient.get() - .uri("$baseUrl/v1/owner/$uuid/wallets") - .accept(MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, "Bearer $token") - .retrieve() - .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToFlux() - .collectList() - .awaitSingle() + .uri("$baseUrl/v1/owner/$uuid/wallets") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToFlux() + .collectList() + .awaitSingle() } override suspend fun getWallet(uuid: String?, token: String?, symbol: String): Wallet { logger.info("fetching wallets for $uuid") return webClient.get() - .uri("$baseUrl/v1/owner/$uuid/wallets/$symbol") - .accept(MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, "Bearer $token") - .retrieve() - .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToMono() - .awaitSingle() + .uri("$baseUrl/v1/owner/$uuid/wallets/$symbol") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitSingle() } override suspend fun getOwnerLimits(uuid: String?, token: String?): OwnerLimitsResponse { logger.info("fetching owner limits for $uuid") return webClient.get() - .uri("$baseUrl/v1/owner/$uuid/limits") - .accept(MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, "Bearer $token") - .retrieve() - .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToMono() - .awaitSingle() + .uri("$baseUrl/v1/owner/$uuid/limits") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitSingle() } override suspend fun getDepositTransactions( - uuid: String, - token: String?, - coin: String?, - startTime: Long, - endTime: Long, - limit: Int, - offset: Int + uuid: String, + token: String?, + coin: String?, + startTime: Long?, + endTime: Long?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? ): List { logger.info("fetching deposit transaction history for $uuid") return webClient.post() - .uri("$baseUrl/transaction/deposit/$uuid") - .accept(MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, "Bearer $token") - .body(Mono.just(TransactionRequest(coin, startTime, endTime, limit, offset))) - .retrieve() - .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToFlux() - .collectList() - .awaitFirstOrElse { emptyList() } + .uri("$baseUrl/transaction/deposit/$uuid") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(TransactionRequest(coin, startTime, endTime, limit, offset, ascendingByTime))) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToFlux() + .collectList() + .awaitFirstOrElse { emptyList() } } override suspend fun getWithdrawTransactions( - uuid: String, - token: String?, - coin: String?, - startTime: Long, - endTime: Long, - limit: Int, - offset: Int + uuid: String, + token: String?, + coin: String?, + startTime: Long?, + endTime: Long?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? ): List { logger.info("fetching withdraw transaction history for $uuid") return webClient.post() - .uri("$baseUrl/withdraw/history/$uuid") - .accept(MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, "Bearer $token") - .body(Mono.just(TransactionRequest(coin, startTime, endTime, limit, offset))) - .retrieve() - .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToFlux() - .collectList() - .awaitFirstOrElse { emptyList() } + .uri("$baseUrl/withdraw/history/$uuid") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(TransactionRequest(coin, startTime, endTime, limit, offset, ascendingByTime))) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToFlux() + .collectList() + .awaitFirstOrElse { emptyList() } } + + } \ No newline at end of file diff --git a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Deposit.kt b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Deposit.kt index 7576d9a0c..01b728da9 100644 --- a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Deposit.kt +++ b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Deposit.kt @@ -1,14 +1,16 @@ package co.nilin.opex.bcgateway.core.model import java.math.BigDecimal +import java.time.LocalDateTime data class Deposit( - val id: Long?, - val hash: String, - val depositor: String, - val depositorMemo: String?, - val amount: BigDecimal, - val chain: String, - val token: Boolean, - val tokenAddress: String? + val id: Long?, + val hash: String, + val depositor: String, + val depositorMemo: String?, + val amount: BigDecimal, + val chain: String, + val token: Boolean, + val tokenAddress: String?, + ) \ No newline at end of file diff --git a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/service/WalletSyncServiceImpl.kt b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/service/WalletSyncServiceImpl.kt index a33db4b2f..997811691 100644 --- a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/service/WalletSyncServiceImpl.kt +++ b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/service/WalletSyncServiceImpl.kt @@ -58,6 +58,6 @@ class WalletSyncServiceImpl( val amount = transfer.amount.divide(BigDecimal.TEN.pow(currencyImpl.decimal)) val symbol = currencyImpl.currency.symbol logger.info("Sending deposit to $uuid - $amount $symbol") - walletProxy.transfer(uuid, symbol, amount, transfer.txHash) + walletProxy.transfer(uuid, symbol, amount, transfer.txHash,transfer.chain) } } diff --git a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/DepositHandler.kt b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/DepositHandler.kt index 4454d7d3e..a8373e322 100644 --- a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/DepositHandler.kt +++ b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/DepositHandler.kt @@ -5,4 +5,6 @@ import co.nilin.opex.bcgateway.core.model.Deposit interface DepositHandler { suspend fun findDepositsByHash(hash: List): List suspend fun saveAll(deposits: List) + + } \ No newline at end of file diff --git a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/WalletProxy.kt b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/WalletProxy.kt index acc5c683f..1c932e776 100644 --- a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/WalletProxy.kt +++ b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/WalletProxy.kt @@ -3,5 +3,5 @@ package co.nilin.opex.bcgateway.core.spi import java.math.BigDecimal interface WalletProxy { - suspend fun transfer(uuid: String, symbol: String, amount: BigDecimal, hash: String) + suspend fun transfer(uuid: String, symbol: String, amount: BigDecimal, hash: String, chain: String) } diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/DepositHandlerImpl.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/DepositHandlerImpl.kt index 3d3f63438..9e475a2f3 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/DepositHandlerImpl.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/DepositHandlerImpl.kt @@ -7,6 +7,7 @@ import co.nilin.opex.bcgateway.ports.postgres.model.DepositModel import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.reactor.awaitSingle +import kotlinx.coroutines.reactor.awaitSingleOrNull import org.springframework.stereotype.Component @Component @@ -14,7 +15,7 @@ class DepositHandlerImpl(private val depositRepository: DepositRepository) : Dep override suspend fun findDepositsByHash(hash: List): List { return depositRepository.findAllByHash(hash).map { Deposit( - it.id, it.hash, it.depositor, it.depositorMemo, it.amount, it.chain, it.token, it.tokenAddress + it.id, it.hash, it.depositor, it.depositorMemo, it.amount, it.chain, it.token, it.tokenAddress ) }.toList() } @@ -22,8 +23,11 @@ class DepositHandlerImpl(private val depositRepository: DepositRepository) : Dep override suspend fun saveAll(deposits: List) { depositRepository.saveAll(deposits.map { DepositModel( - null, it.hash, it.depositor, it.depositorMemo, it.amount, it.chain, it.token, it.tokenAddress + null, it.hash, it.depositor, it.depositorMemo, it.amount, it.chain, it.token, it.tokenAddress ) }).collectList().awaitSingle() } + + + } diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/DepositModel.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/DepositModel.kt index 87b10c847..6b6c411a2 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/DepositModel.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/DepositModel.kt @@ -4,6 +4,7 @@ import org.springframework.data.annotation.Id import org.springframework.data.relational.core.mapping.Column import org.springframework.data.relational.core.mapping.Table import java.math.BigDecimal +import java.time.LocalDateTime @Table("deposits") data class DepositModel( @@ -14,5 +15,5 @@ data class DepositModel( val amount: BigDecimal, val chain: String, val token: Boolean, - val tokenAddress: String? + val tokenAddress: String?, ) \ No newline at end of file diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/schema.sql b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/schema.sql index 2913a0b24..2bbbb39af 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/schema.sql +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/schema.sql @@ -90,3 +90,6 @@ CREATE TABLE IF NOT EXISTS deposits depositor VARCHAR(72) NOT NULL, depositor_memo VARCHAR(72) ); + + + diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-wallet-proxy/src/main/kotlin/co/nilin/opex/bcgateway/ports/walletproxy/impl/WalletProxyImpl.kt b/bc-gateway/bc-gateway-ports/bc-gateway-wallet-proxy/src/main/kotlin/co/nilin/opex/bcgateway/ports/walletproxy/impl/WalletProxyImpl.kt index e8cc1b442..f8152054a 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-wallet-proxy/src/main/kotlin/co/nilin/opex/bcgateway/ports/walletproxy/impl/WalletProxyImpl.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-wallet-proxy/src/main/kotlin/co/nilin/opex/bcgateway/ports/walletproxy/impl/WalletProxyImpl.kt @@ -33,11 +33,11 @@ class WalletProxyImpl(private val webClient: WebClient, // } - override suspend fun transfer(uuid: String, symbol: String, amount: BigDecimal, hash: String) { + override suspend fun transfer(uuid: String, symbol: String, amount: BigDecimal, hash: String, chain: String) { val token = extractBackgroundAuth.extractToken() webClient.post() - .uri(URI.create("$baseUrl/deposit/${amount}_${symbol}/${uuid}_main?transferRef=$hash")) + .uri(URI.create("$baseUrl/deposit/${amount}_${chain}_${symbol}/${uuid}_main?transferRef=$hash")) .headers { httpHeaders -> run { httpHeaders.add("Content-Type", "application/json"); diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/MarketStatsController.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/MarketStatsController.kt index 058e89b40..ecd3401f7 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/MarketStatsController.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/MarketStatsController.kt @@ -1,14 +1,17 @@ package co.nilin.opex.market.app.controller import co.nilin.opex.common.utils.Interval -import co.nilin.opex.market.app.utils.asLocalDateTime import co.nilin.opex.market.core.inout.PriceStat import co.nilin.opex.market.core.inout.TradeVolumeStat +import co.nilin.opex.market.core.inout.Transaction +import co.nilin.opex.market.core.inout.TxOfTrades import co.nilin.opex.market.core.spi.MarketQueryHandler import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController +import java.time.LocalDateTime import java.util.* @RestController @@ -35,4 +38,6 @@ class MarketStatsController(private val marketQueryHandler: MarketQueryHandler) return marketQueryHandler.mostTrades(interval) } + + } \ No newline at end of file diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt index fba688952..e95fbe9ea 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt @@ -3,7 +3,10 @@ package co.nilin.opex.market.app.controller import co.nilin.opex.common.OpexError import co.nilin.opex.market.core.inout.* import co.nilin.opex.market.core.spi.UserQueryHandler +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* +import java.time.LocalDateTime @RestController @RequestMapping("/v1/user") @@ -21,9 +24,9 @@ class UserDataController(private val userQueryHandler: UserQueryHandler) { @GetMapping("/{uuid}/orders/{symbol}/open") suspend fun getUserOpenOrders( - @PathVariable uuid: String, - @PathVariable symbol: String, - @RequestParam limit: Int + @PathVariable uuid: String, + @PathVariable symbol: String, + @RequestParam limit: Int ): List { return userQueryHandler.openOrders(uuid, symbol, limit) } @@ -38,4 +41,13 @@ class UserDataController(private val userQueryHandler: UserQueryHandler) { return userQueryHandler.allTrades(uuid, request) } + @GetMapping("/tx/{user}/history") + suspend fun getTxOfTrades(@PathVariable user: String, + @RequestBody transactionRequest: TransactionRequest, + @CurrentSecurityContext securityContext: SecurityContext): TxOfTrades? { + if (securityContext != null && securityContext.authentication.name != user) + throw OpexError.Forbidden.exception() + return userQueryHandler.txOfTrades(transactionRequest.apply { owner = user }) + } + } \ No newline at end of file diff --git a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt new file mode 100644 index 000000000..267387369 --- /dev/null +++ b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt @@ -0,0 +1,17 @@ +package co.nilin.opex.market.core.inout + +import java.math.BigDecimal +import java.time.LocalDateTime + +data class Transaction( + var createDate: LocalDateTime, + var volume: BigDecimal, + val transactionPrice: BigDecimal, + var matchedPrice: BigDecimal, + var side: String, + var symbol: String, + var fee: BigDecimal, + var user: String?=null +) + +data class TxOfTrades(var transaction:List?) \ No newline at end of file diff --git a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionRequest.kt b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionRequest.kt new file mode 100644 index 000000000..d9f66d6a4 --- /dev/null +++ b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionRequest.kt @@ -0,0 +1,12 @@ +package co.nilin.opex.market.core.inout + +data class TransactionRequest( + val coin: String?, + val category: String?, + val startTime: Long? = null, + val endTime: Long? = null, + val limit: Int? = 10, + val offset: Int? = 0, + val ascendingByTime: Boolean? = false, + var owner: String? = null +) \ No newline at end of file diff --git a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/MarketQueryHandler.kt b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/MarketQueryHandler.kt index bb0243e69..37e644c6c 100644 --- a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/MarketQueryHandler.kt +++ b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/MarketQueryHandler.kt @@ -2,6 +2,7 @@ package co.nilin.opex.market.core.spi import co.nilin.opex.common.utils.Interval import co.nilin.opex.market.core.inout.* +import java.time.LocalDateTime interface MarketQueryHandler { @@ -22,11 +23,11 @@ interface MarketQueryHandler { suspend fun getBestPriceForSymbols(symbols: List): List suspend fun getCandleInfo( - symbol: String, - interval: String, - startTime: Long?, - endTime: Long?, - limit: Int + symbol: String, + interval: String, + startTime: Long?, + endTime: Long?, + limit: Int ): List suspend fun numberOfActiveUsers(interval: Interval): Long @@ -43,4 +44,5 @@ interface MarketQueryHandler { suspend fun mostTrades(interval: Interval): TradeVolumeStat? + } \ No newline at end of file diff --git a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt index 18bc94542..a168de797 100644 --- a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt +++ b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt @@ -1,6 +1,7 @@ package co.nilin.opex.market.core.spi import co.nilin.opex.market.core.inout.* +import java.time.LocalDateTime interface UserQueryHandler { @@ -13,4 +14,7 @@ interface UserQueryHandler { suspend fun allOrders(uuid: String, allOrderRequest: AllOrderRequest): List suspend fun allTrades(uuid: String, request: TradeRequest): List + + suspend fun txOfTrades(transactionRequest: TransactionRequest): TxOfTrades? + } \ No newline at end of file diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt index 44405d192..a5ab2053a 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt @@ -3,11 +3,13 @@ package co.nilin.opex.market.ports.postgres.dao import co.nilin.opex.market.core.inout.BestPrice import co.nilin.opex.market.core.inout.PriceStat import co.nilin.opex.market.core.inout.TradeVolumeStat +import co.nilin.opex.market.core.inout.Transaction import co.nilin.opex.market.ports.postgres.model.CandleInfoData import co.nilin.opex.market.ports.postgres.model.LastPrice import co.nilin.opex.market.ports.postgres.model.TradeModel import co.nilin.opex.market.ports.postgres.model.TradeTickerData import kotlinx.coroutines.flow.Flow +import org.springframework.data.domain.Pageable import org.springframework.data.r2dbc.repository.Query import org.springframework.data.repository.query.Param import org.springframework.data.repository.reactive.ReactiveCrudRepository @@ -27,7 +29,7 @@ interface TradeRepository : ReactiveCrudRepository { fun findMostRecentBySymbol(symbol: String): Flow @Query( - """ + """ select * from trades where :uuid in (taker_uuid, maker_uuid) and (:fromTrade is null or id > :fromTrade) and (:symbol is null or symbol = :symbol) @@ -37,29 +39,29 @@ interface TradeRepository : ReactiveCrudRepository { """ ) fun findByUuidAndSymbolAndTimeBetweenAndTradeIdGreaterThan( - @Param("uuid") - uuid: String, - @Param("symbol") - symbol: String?, - @Param("fromTrade") - fromTrade: Long?, - @Param("startTime") - startTime: Date?, - @Param("endTime") - endTime: Date?, - limit: Int + @Param("uuid") + uuid: String, + @Param("symbol") + symbol: String?, + @Param("fromTrade") + fromTrade: Long?, + @Param("startTime") + startTime: Date?, + @Param("endTime") + endTime: Date?, + limit: Int ): Flow @Query("select * from trades where symbol = :symbol order by create_date desc limit :limit") fun findBySymbolSortDescendingByCreateDate( - @Param("symbol") - symbol: String, - @Param("limit") - limit: Int + @Param("symbol") + symbol: String, + @Param("limit") + limit: Int ): Flow @Query( - """ + """ with first_trade as (select id, symbol, matched_price, matched_quantity from trades where id in (select min(id) from trades where create_date > :date group by symbol)), last_trade as (select id, symbol, matched_price, matched_quantity from trades where id in (select max(id) from trades where create_date > :date group by symbol)) select symbol, @@ -100,7 +102,7 @@ interface TradeRepository : ReactiveCrudRepository { fun tradeTicker(@Param("date") createDate: LocalDateTime): Flux @Query( - """ + """ with first_trade as (select * from trades where create_date > :date and symbol = :symbol order by create_date limit 1), last_trade as (select * from trades where create_date > :date and symbol = :symbol order by create_date desc limit 1) select symbol, @@ -139,14 +141,14 @@ interface TradeRepository : ReactiveCrudRepository { """ ) fun tradeTickerBySymbol( - @Param("symbol") - symbol: String, - @Param("date") - createDate: LocalDateTime, + @Param("symbol") + symbol: String, + @Param("date") + createDate: LocalDateTime, ): Mono @Query( - """ + """ select symbol, ( select price from orders @@ -167,7 +169,7 @@ interface TradeRepository : ReactiveCrudRepository { fun bestAskAndBidPrice(): Flux @Query( - """ + """ select symbol, ( select price from orders @@ -189,7 +191,7 @@ interface TradeRepository : ReactiveCrudRepository { fun bestAskAndBidPrice(symbols: List): Flux @Query( - """ + """ select symbol, ( select price from orders @@ -217,7 +219,7 @@ interface TradeRepository : ReactiveCrudRepository { fun findAllGroupBySymbol(): Flux @Query( - """ + """ WITH intervals AS (SELECT * FROM interval_generator((:startTime), (:endTime), :interval ::INTERVAL)), first_trade AS ( SELECT DISTINCT ON (f.start_time) f.start_time, f.end_time, t.matched_price AS open_price FROM intervals f @@ -249,16 +251,16 @@ interface TradeRepository : ReactiveCrudRepository { """ ) suspend fun candleData( - @Param("symbol") - symbol: String, - @Param("interval") - interval: String, - @Param("startTime") - startTime: LocalDateTime, - @Param("endTime") - endTime: LocalDateTime, - @Param("limit") - limit: Int, + @Param("symbol") + symbol: String, + @Param("interval") + interval: String, + @Param("startTime") + startTime: LocalDateTime, + @Param("endTime") + endTime: LocalDateTime, + @Param("limit") + limit: Int, ): Flux @Query("select * from trades order by create_date desc limit 1") @@ -274,7 +276,7 @@ interface TradeRepository : ReactiveCrudRepository { fun countBySymbolNewerThan(interval: LocalDateTime, symbol: String): Flow @Query( - """ + """ WITH first_trade AS (SELECT symbol, MIN(id) AS min_id FROM trades WHERE create_date > :since GROUP BY symbol), last_trade AS (SELECT symbol, MAX(id) AS max_id FROM trades WHERE create_date > :since GROUP BY symbol), first_trade_details AS (SELECT ft.symbol, t.matched_price AS first_price FROM first_trade ft JOIN trades t ON ft.min_id = t.id), @@ -296,7 +298,7 @@ interface TradeRepository : ReactiveCrudRepository { fun findByMostIncreasedPrice(since: LocalDateTime, limit: Int): Flux @Query( - """ + """ WITH first_trade AS (SELECT symbol, MIN(id) AS min_id FROM trades WHERE create_date > :since GROUP BY symbol), last_trade AS (SELECT symbol, MAX(id) AS max_id FROM trades WHERE create_date > :since GROUP BY symbol), first_trade_details AS (SELECT ft.symbol, t.matched_price AS first_price FROM first_trade ft JOIN trades t ON ft.min_id = t.id), @@ -318,7 +320,7 @@ interface TradeRepository : ReactiveCrudRepository { fun findByMostDecreasedPrice(since: LocalDateTime, limit: Int): Flux @Query( - """ + """ with first_trade as (select symbol, matched_quantity mq from trades where id in (select min(id) from trades where create_date > :since group by symbol)), last_trade as (select symbol, matched_quantity mq from trades where id in (select max(id) from trades where create_date > :since group by symbol)) select @@ -342,7 +344,7 @@ interface TradeRepository : ReactiveCrudRepository { fun findByMostVolume(since: LocalDateTime): Mono @Query( - """ + """ with first_trade as (select symbol, matched_quantity mq from trades where id in (select min(id) from trades where create_date > :since group by symbol)), last_trade as (select symbol, matched_quantity mq from trades where id in (select max(id) from trades where create_date > :since group by symbol)) select @@ -364,4 +366,52 @@ interface TradeRepository : ReactiveCrudRepository { """ ) fun findByMostTrades(since: LocalDateTime): Mono + + + @Query(""" select t.trade_date As create_date, + t.matched_quantity AS volume, + t.matched_price AS matched_price, + CASE + WHEN t.maker_uuid = :user THEN t.maker_commission + WHEN t.taker_uuid = :user THEN t.taker_commission + END AS fee, + CASE + WHEN t.maker_uuid = :user THEN o1.side + WHEN t.taker_uuid = :user THEN o2.side + END AS side, + t.matched_price * t.matched_quantity as transaction_price, + substring(t.symbol, 0, position('_' in t.symbol) ) AS symbol + FROM trades t + INNER JOIN orders o1 ON t.maker_ouid = o1.ouid + LEFT JOIN orders o2 ON t.taker_ouid = o2.ouid + WHERE (t.maker_uuid = :user OR t.taker_uuid = :user) + and (:startDate is null or trade_date >=:startDate) + and (:endDate is null or trade_date <=:endDate) + order by trade_date DESC offset :offset limit :limit """) + fun findTxOfTradesDesc(user: String, startDate: LocalDateTime?, endDate: LocalDateTime?, offset: Int?, limit: Int?): Flux + + + @Query(""" select t.trade_date As create_date, + t.matched_quantity AS volume, + t.matched_price AS matched_price, + CASE + WHEN t.maker_uuid = :user THEN t.maker_commission + WHEN t.taker_uuid = :user THEN t.taker_commission + END AS fee, + CASE + WHEN t.maker_uuid = :user THEN o1.side + WHEN t.taker_uuid = :user THEN o2.side + END AS side, + t.matched_price * t.matched_quantity as transaction_price, + substring(t.symbol, 0, position('_' in t.symbol) ) AS symbol + FROM trades t + INNER JOIN orders o1 ON t.maker_ouid = o1.ouid + LEFT JOIN orders o2 ON t.taker_ouid = o2.ouid + WHERE (t.maker_uuid = :user OR t.taker_uuid = :user) + and (:startDate is null or trade_date >=:startDate) + and (:endDate is null or trade_date <=:endDate) + order by trade_date ASC offset :offset limit :limit """) + fun findTxOfTradesAsc(user: String, startDate: LocalDateTime?, endDate: LocalDateTime?, offset: Int?, limit: Int?): Flux + + } \ No newline at end of file diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt index c04159e50..e3dba3aed 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt @@ -17,6 +17,8 @@ import kotlinx.coroutines.reactive.awaitFirst import kotlinx.coroutines.reactive.awaitFirstOrElse import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactor.awaitSingleOrNull +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Sort import org.springframework.stereotype.Component import java.math.BigDecimal import java.time.Instant @@ -26,10 +28,10 @@ import java.util.* @Component class MarketQueryHandlerImpl( - private val orderRepository: OrderRepository, - private val tradeRepository: TradeRepository, - private val orderStatusRepository: OrderStatusRepository, - private val redisCacheHelper: RedisCacheHelper + private val orderRepository: OrderRepository, + private val tradeRepository: TradeRepository, + private val orderStatusRepository: OrderStatusRepository, + private val redisCacheHelper: RedisCacheHelper ) : MarketQueryHandler { //TODO merge order and status fetching in query @@ -37,9 +39,9 @@ class MarketQueryHandlerImpl( override suspend fun getTradeTickerData(interval: Interval): List { return redisCacheHelper.getOrElse("tradeTickerData:${interval.label}", 2.minutes()) { tradeRepository.tradeTicker(interval.getLocalDateTime()) - .collectList() - .awaitFirstOrElse { emptyList() } - .map { it.asPriceChangeResponse(Date().time, interval.getTime()) } + .collectList() + .awaitFirstOrElse { emptyList() } + .map { it.asPriceChangeResponse(Date().time, interval.getTime()) } } } @@ -47,31 +49,31 @@ class MarketQueryHandlerImpl( val cacheId = "tradeTickerData:$symbol:${interval.label}" return redisCacheHelper.getOrElse(cacheId, 2.minutes()) { tradeRepository.tradeTickerBySymbol(symbol, interval.getLocalDateTime()) - .awaitFirstOrNull() - ?.asPriceChangeResponse(Date().time, interval.getTime()) + .awaitFirstOrNull() + ?.asPriceChangeResponse(Date().time, interval.getTime()) } } override suspend fun openBidOrders(symbol: String, limit: Int): List { return orderRepository.findBySymbolAndDirectionAndStatusSortDescendingByPrice( - symbol, - OrderDirection.BID, - limit, - listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) + symbol, + OrderDirection.BID, + limit, + listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) ).collectList() - .awaitFirstOrElse { emptyList() } - .map { OrderBook(it.price, it.quantity) } + .awaitFirstOrElse { emptyList() } + .map { OrderBook(it.price, it.quantity) } } override suspend fun openAskOrders(symbol: String, limit: Int): List { return orderRepository.findBySymbolAndDirectionAndStatusSortAscendingByPrice( - symbol, - OrderDirection.ASK, - limit, - listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) + symbol, + OrderDirection.ASK, + limit, + listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) ).collectList() - .awaitFirstOrElse { emptyList() } - .map { OrderBook(it.price, it.quantity) } + .awaitFirstOrElse { emptyList() } + .map { OrderBook(it.price, it.quantity) } } // @Cacheable does not support suspended functions. Spring 6.1 required. @@ -92,28 +94,28 @@ class MarketQueryHandlerImpl( return recentTradesCache.toList() return tradeRepository.findBySymbolSortDescendingByCreateDate(symbol, limit) - .map { - val takerOrder = orderRepository.findByOuid(it.takerOuid).awaitFirst() - val makerOrder = orderRepository.findByOuid(it.makerOuid).awaitFirst() - val isMakerBuyer = makerOrder.direction == OrderDirection.BID - MarketTrade( - it.symbol, - it.baseAsset, - it.quoteAsset, - it.tradeId, - it.matchedPrice, - it.matchedQuantity, - if (isMakerBuyer) - makerOrder.quoteQuantity!! - else - takerOrder.quoteQuantity!!, - Date.from(it.createDate.atZone(ZoneId.systemDefault()).toInstant()), - true, - isMakerBuyer - ) - }.toList() - .onEach { redisCacheHelper.putListItem(cacheKey, it) } - .also { redisCacheHelper.setExpiration(cacheKey, 60.minutes()) } + .map { + val takerOrder = orderRepository.findByOuid(it.takerOuid).awaitFirst() + val makerOrder = orderRepository.findByOuid(it.makerOuid).awaitFirst() + val isMakerBuyer = makerOrder.direction == OrderDirection.BID + MarketTrade( + it.symbol, + it.baseAsset, + it.quoteAsset, + it.tradeId, + it.matchedPrice, + it.matchedQuantity, + if (isMakerBuyer) + makerOrder.quoteQuantity!! + else + takerOrder.quoteQuantity!!, + Date.from(it.createDate.atZone(ZoneId.systemDefault()).toInstant()), + true, + isMakerBuyer + ) + }.toList() + .onEach { redisCacheHelper.putListItem(cacheKey, it) } + .also { redisCacheHelper.setExpiration(cacheKey, 60.minutes()) } } override suspend fun lastPrice(symbol: String?): List { @@ -130,17 +132,17 @@ class MarketQueryHandlerImpl( val id = symbols.joinToString { it } return redisCacheHelper.getOrElse("bestPricesForSymbols:$id", 1.minutes()) { tradeRepository.bestAskAndBidPrice(symbols) - .collectList() - .awaitFirstOrElse { emptyList() } + .collectList() + .awaitFirstOrElse { emptyList() } } } override suspend fun getCandleInfo( - symbol: String, - interval: String, - startTime: Long?, - endTime: Long?, - limit: Int + symbol: String, + interval: String, + startTime: Long?, + endTime: Long?, + limit: Int ): List { val st = if (startTime == null) tradeRepository.findFirstByCreateDate().awaitFirstOrNull()?.createDate ?: LocalDateTime.now() @@ -157,23 +159,23 @@ class MarketQueryHandlerImpl( } return tradeRepository.candleData(symbol, interval, st, et, limit) - .collectList() - .awaitFirstOrElse { emptyList() } - .map { - CandleData( - it.openTime, - it.closeTime, - it.open ?: BigDecimal.ZERO, - it.close ?: BigDecimal.ZERO, - it.high ?: BigDecimal.ZERO, - it.low ?: BigDecimal.ZERO, - it.volume ?: BigDecimal.ZERO, - BigDecimal.ZERO, - it.trades, - BigDecimal.ZERO, - BigDecimal.ZERO - ) - } + .collectList() + .awaitFirstOrElse { emptyList() } + .map { + CandleData( + it.openTime, + it.closeTime, + it.open ?: BigDecimal.ZERO, + it.close ?: BigDecimal.ZERO, + it.high ?: BigDecimal.ZERO, + it.low ?: BigDecimal.ZERO, + it.volume ?: BigDecimal.ZERO, + BigDecimal.ZERO, + it.trades, + BigDecimal.ZERO, + BigDecimal.ZERO + ) + } } override suspend fun numberOfActiveUsers(interval: Interval): Long { @@ -207,16 +209,16 @@ class MarketQueryHandlerImpl( override suspend fun mostIncreasePrice(interval: Interval, limit: Int): List { return redisCacheHelper.getOrElse("priceIncrease:${interval.label}", 1.minutes()) { tradeRepository.findByMostIncreasedPrice(interval.getLocalDateTime(), limit) - .collectList() - .awaitFirstOrElse { emptyList() } + .collectList() + .awaitFirstOrElse { emptyList() } }.take(limit) } override suspend fun mostDecreasePrice(interval: Interval, limit: Int): List { return redisCacheHelper.getOrElse("priceDecrease:${interval.label}", 1.minutes()) { tradeRepository.findByMostDecreasedPrice(interval.getLocalDateTime(), limit) - .collectList() - .awaitFirstOrElse { emptyList() } + .collectList() + .awaitFirstOrElse { emptyList() } }.take(limit) } @@ -233,22 +235,25 @@ class MarketQueryHandlerImpl( } private fun TradeTickerData.asPriceChangeResponse(openTime: Long, closeTime: Long) = PriceChange( - symbol, - priceChange ?: BigDecimal.ZERO, - priceChangePercent ?: BigDecimal.ZERO, - weightedAvgPrice ?: BigDecimal.ZERO, - lastPrice ?: BigDecimal.ZERO, - lastQty ?: BigDecimal.ZERO, - bidPrice ?: BigDecimal.ZERO, - askPrice ?: BigDecimal.ZERO, - openPrice ?: BigDecimal.ZERO, - highPrice ?: BigDecimal.ZERO, - lowPrice ?: BigDecimal.ZERO, - volume ?: BigDecimal.ZERO, - openTime, - closeTime, - firstId ?: -1, - lastId ?: -1, - count ?: 0 + symbol, + priceChange ?: BigDecimal.ZERO, + priceChangePercent ?: BigDecimal.ZERO, + weightedAvgPrice ?: BigDecimal.ZERO, + lastPrice ?: BigDecimal.ZERO, + lastQty ?: BigDecimal.ZERO, + bidPrice ?: BigDecimal.ZERO, + askPrice ?: BigDecimal.ZERO, + openPrice ?: BigDecimal.ZERO, + highPrice ?: BigDecimal.ZERO, + lowPrice ?: BigDecimal.ZERO, + volume ?: BigDecimal.ZERO, + openTime, + closeTime, + firstId ?: -1, + lastId ?: -1, + count ?: 0 ) + + } + diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt index 5375c9bd3..0a6ea4ded 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt @@ -13,23 +13,27 @@ import kotlinx.coroutines.flow.toList import kotlinx.coroutines.reactive.awaitFirst import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactor.awaitSingleOrNull +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Sort import org.springframework.stereotype.Component +import java.time.Instant +import java.time.LocalDateTime import java.time.ZoneId import java.util.* @Component class UserQueryHandlerImpl( - private val orderRepository: OrderRepository, - private val tradeRepository: TradeRepository, - private val orderStatusRepository: OrderStatusRepository + private val orderRepository: OrderRepository, + private val tradeRepository: TradeRepository, + private val orderStatusRepository: OrderStatusRepository ) : UserQueryHandler { //TODO merge order and status fetching in query override suspend fun getOrder(uuid: String, ouid: String): Order? { return orderRepository.findByUUIDAndOUID(uuid, ouid) - .awaitSingleOrNull() - ?.asOrderDTO(orderStatusRepository.findMostRecentByOUID(ouid).awaitFirstOrNull()) + .awaitSingleOrNull() + ?.asOrderDTO(orderStatusRepository.findMostRecentByOUID(ouid).awaitFirstOrNull()) } override suspend fun queryOrder(uuid: String, request: QueryOrderRequest): Order? { @@ -48,52 +52,72 @@ class UserQueryHandlerImpl( override suspend fun openOrders(uuid: String, symbol: String?, limit: Int): List { return orderRepository.findByUuidAndSymbolAndStatus( - uuid, - symbol, - listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code), - limit + uuid, + symbol, + listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code), + limit ).filter { orderModel -> orderModel.constraint != null } - .map { it.asOrderDTO(orderStatusRepository.findMostRecentByOUID(it.ouid).awaitFirstOrNull()) } - .toList() + .map { it.asOrderDTO(orderStatusRepository.findMostRecentByOUID(it.ouid).awaitFirstOrNull()) } + .toList() } override suspend fun allOrders(uuid: String, allOrderRequest: AllOrderRequest): List { return orderRepository.findByUuidAndSymbolAndTimeBetween( - uuid, - allOrderRequest.symbol, - allOrderRequest.startTime, - allOrderRequest.endTime, - allOrderRequest.limit + uuid, + allOrderRequest.symbol, + allOrderRequest.startTime, + allOrderRequest.endTime, + allOrderRequest.limit ).filter { orderModel -> orderModel.constraint != null } - .map { it.asOrderDTO(orderStatusRepository.findMostRecentByOUID(it.ouid).awaitFirstOrNull()) } - .toList() + .map { it.asOrderDTO(orderStatusRepository.findMostRecentByOUID(it.ouid).awaitFirstOrNull()) } + .toList() } override suspend fun allTrades(uuid: String, request: TradeRequest): List { return tradeRepository.findByUuidAndSymbolAndTimeBetweenAndTradeIdGreaterThan( - uuid, request.symbol, request.fromTrade, request.startTime, request.endTime, request.limit + uuid, request.symbol, request.fromTrade, request.startTime, request.endTime, request.limit ).map { val takerOrder = orderRepository.findByOuid(it.takerOuid).awaitFirst() val makerOrder = orderRepository.findByOuid(it.makerOuid).awaitFirst() val isMakerBuyer = makerOrder.direction == OrderDirection.BID Trade( - it.symbol, - it.tradeId, - if (it.takerUuid == uuid) takerOrder.orderId!! else makerOrder.orderId!!, - if (it.takerUuid == uuid) it.takerPrice else it.makerPrice, - it.matchedQuantity, - if (isMakerBuyer) makerOrder.quoteQuantity!! else takerOrder.quoteQuantity!!, - if (it.takerUuid == uuid) it.takerCommission!! else it.makerCommission!!, - if (it.takerUuid == uuid) it.takerCommissionAsset!! else it.makerCommissionAsset!!, - Date.from(it.createDate.atZone(ZoneId.systemDefault()).toInstant()), - if (it.takerUuid == uuid) - OrderDirection.ASK == takerOrder.direction - else - OrderDirection.ASK == makerOrder.direction, - it.makerUuid == uuid, - true, - isMakerBuyer + it.symbol, + it.tradeId, + if (it.takerUuid == uuid) takerOrder.orderId!! else makerOrder.orderId!!, + if (it.takerUuid == uuid) it.takerPrice else it.makerPrice, + it.matchedQuantity, + if (isMakerBuyer) makerOrder.quoteQuantity!! else takerOrder.quoteQuantity!!, + if (it.takerUuid == uuid) it.takerCommission!! else it.makerCommission!!, + if (it.takerUuid == uuid) it.takerCommissionAsset!! else it.makerCommissionAsset!!, + Date.from(it.createDate.atZone(ZoneId.systemDefault()).toInstant()), + if (it.takerUuid == uuid) + OrderDirection.ASK == takerOrder.direction + else + OrderDirection.ASK == makerOrder.direction, + it.makerUuid == uuid, + true, + isMakerBuyer ) }.toList() } + + override suspend fun txOfTrades(transactionRequest: TransactionRequest): TxOfTrades? { + + if (transactionRequest.ascendingByTime == true) + return TxOfTrades(tradeRepository.findTxOfTradesAsc(transactionRequest.owner!!, + transactionRequest.startTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.startTime!!), ZoneId.systemDefault()) } + ?: null, + transactionRequest.endTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.endTime!!), ZoneId.systemDefault()) } + ?: null, + transactionRequest.offset, transactionRequest.limit + ).collectList()?.awaitFirstOrNull()) + else + return TxOfTrades(tradeRepository.findTxOfTradesDesc(transactionRequest.owner!!, + transactionRequest.startTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.startTime!!), ZoneId.systemDefault()) } + ?: null, + transactionRequest.endTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.endTime!!), ZoneId.systemDefault()) } + ?: null, + transactionRequest.offset, transactionRequest.limit + ).collectList()?.awaitFirstOrNull()) + } } \ No newline at end of file diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt index 78f59fbb0..89401d27e 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt @@ -30,6 +30,8 @@ class SecurityConfig(private val webClient: WebClient) { .pathMatchers("/balanceOf/**").hasAuthority("SCOPE_trust") .pathMatchers("/owner/**").hasAuthority("SCOPE_trust") .pathMatchers("/withdraw").hasAuthority("SCOPE_trust") + .pathMatchers("/deposit/manually").hasRole("SCOPE_trust", "admin_finance") + .pathMatchers("/deposit/**").hasAuthority("SCOPE_trust") .pathMatchers("/withdraw/**").hasAuthority("SCOPE_trust") .pathMatchers("/transaction/**").hasAuthority("SCOPE_trust") .pathMatchers("/admin/**").hasRole("SCOPE_trust", "admin_finance") diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt new file mode 100644 index 000000000..1ea6d5c58 --- /dev/null +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt @@ -0,0 +1,86 @@ +package co.nilin.opex.wallet.app.controller + +import co.nilin.opex.common.OpexError +import co.nilin.opex.wallet.app.dto.ManualTransferRequest +import co.nilin.opex.wallet.app.dto.TransactionRequest +import co.nilin.opex.wallet.app.dto.WithdrawHistoryResponse +import co.nilin.opex.wallet.app.service.TransferService +import co.nilin.opex.wallet.core.inout.* +import co.nilin.opex.wallet.core.service.WithdrawService +import co.nilin.opex.wallet.core.spi.DepositPersister +import io.swagger.annotations.ApiResponse +import io.swagger.annotations.Example +import io.swagger.annotations.ExampleProperty +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* +import java.math.BigDecimal +import java.security.Principal +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId + +@RestController +@RequestMapping("/v1/deposit") +class DepositController(private val depositPersister: DepositPersister, + private val transferService: TransferService) { + + + @PostMapping("/{uuid}/history") + suspend fun getDepositTransactionsForUser( + @PathVariable("uuid") uuid: String, + @RequestBody request: TransactionRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): Deposits { + if (securityContext!=null && securityContext.authentication.name != uuid) + throw OpexError.Forbidden.exception() + return Deposits(depositPersister.findDepositHistory( + uuid, + request.coin, + request.startTime?.let { + LocalDateTime.ofInstant(Instant.ofEpochMilli(request.startTime), ZoneId.systemDefault()) + } + ?: null, + request.endTime?.let { + LocalDateTime.ofInstant(Instant.ofEpochMilli(request.endTime), ZoneId.systemDefault()) + } ?: null, + request.limit!!, + request.offset!!, + request.ascendingByTime + ).deposits.map { + it.apply { it.createDate?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli() } + + }) + } + + + + + @PostMapping("/manually/{amount}_{symbol}/{receiverUuid}") + @ApiResponse( + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ }", + mediaType = "application/json" + ) + ) + ) + suspend fun depositManually( + @PathVariable("symbol") symbol: String, + @PathVariable("receiverUuid") receiverUuid: String, + @PathVariable("amount") amount: BigDecimal, + @RequestBody request: ManualTransferRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): TransferResult { + + return transferService.depositManually(symbol, receiverUuid, + securityContext.authentication.name, amount, request) + } + + +} + + + diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransactionController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransactionController.kt index 2f21cd6ea..7540c1e44 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransactionController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransactionController.kt @@ -28,7 +28,8 @@ class TransactionController(private val manager: TransactionManager) { LocalDateTime.ofInstant(Instant.ofEpochMilli(request.endTime), ZoneId.systemDefault()) }, request.limit!!, - request.offset!! + request.offset!!, + request.ascendingByTime?:false ) } diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt index 76f85d7b6..00626a2a3 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt @@ -96,7 +96,8 @@ class TransferController(private val transferService: TransferService) { transferService.batchTransfer(request) } - @PostMapping("/deposit/{amount}_{symbol}/{receiverUuid}_{receiverWalletType}") + + @PostMapping("/deposit/{amount}_{chain}_{symbol}/{receiverUuid}_{receiverWalletType}") @ApiResponse( message = "OK", code = 200, @@ -113,33 +114,10 @@ class TransferController(private val transferService: TransferService) { @PathVariable("receiverWalletType") receiverWalletType: String, @PathVariable("amount") amount: BigDecimal, @RequestParam("description") description: String?, - @RequestParam("transferRef") transferRef: String? + @RequestParam("transferRef") transferRef: String?, + @PathVariable("chain") chain: String? ): TransferResult { - return transferService.deposit(symbol, receiverUuid, receiverWalletType, amount, description, transferRef) + return transferService.deposit(symbol, receiverUuid, receiverWalletType, amount, description, transferRef, chain) } - - @PostMapping("/manually/deposit/{amount}_{symbol}/{receiverUuid}") - @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ }", - mediaType = "application/json" - ) - ) - ) - suspend fun depositManually( - @PathVariable("symbol") symbol: String, - @PathVariable("receiverUuid") receiverUuid: String, - @PathVariable("amount") amount: BigDecimal, - @RequestBody request: ManualTransferRequest, - @CurrentSecurityContext securityContext: SecurityContext - ): TransferResult { - - return transferService.depositManually(symbol, receiverUuid, - securityContext.authentication.name - , amount, request) - } } diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt index e8ab509a3..3e9062882 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt @@ -31,82 +31,82 @@ class WithdrawController(private val withdrawService: WithdrawService) { @GetMapping @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ }", - mediaType = "application/json" + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ }", + mediaType = "application/json" + ) ) - ) ) suspend fun getMyWithdraws( - principal: Principal, - @RequestParam("withdraw_id", required = false) withdrawId: String?, - @RequestParam("currency", required = false) currency: String?, - @RequestParam("dest_transaction_ref", required = false) destTxRef: String?, - @RequestParam("dest_address", required = false) destAddress: String?, - @RequestParam("status", required = false) status: List? + principal: Principal, + @RequestParam("withdraw_id", required = false) withdrawId: String?, + @RequestParam("currency", required = false) currency: String?, + @RequestParam("dest_transaction_ref", required = false) destTxRef: String?, + @RequestParam("dest_address", required = false) destAddress: String?, + @RequestParam("status", required = false) status: List? ): List { return withdrawService - .findByCriteria( - principal.name, - withdrawId, - currency, - destTxRef, - destAddress, - status?.isEmpty() ?: true, - status ?: listOf("") - ) + .findByCriteria( + principal.name, + withdrawId, + currency, + destTxRef, + destAddress, + status?.isEmpty() ?: true, + status ?: listOf("") + ) } @PostMapping("/{amount}_{currency}") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ }", - mediaType = "application/json" + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ }", + mediaType = "application/json" + ) ) - ) ) suspend fun requestWithdraw( - principal: Principal, - @PathVariable("currency") currency: String, - @PathVariable("amount") amount: BigDecimal, - @RequestParam("description", required = false) description: String?, - @RequestParam("transferRef", required = false) transferRef: String?, - @RequestParam("fee") fee: BigDecimal, - @RequestParam("destSymbol") destSymbol: String, - @RequestParam("destAddress") destAddress: String, - @RequestParam("destNetwork") destNetwork: String?, - @RequestParam("destNote", required = false) destNote: String?, + principal: Principal, + @PathVariable("currency") currency: String, + @PathVariable("amount") amount: BigDecimal, + @RequestParam("description", required = false) description: String?, + @RequestParam("transferRef", required = false) transferRef: String?, + @RequestParam("fee") fee: BigDecimal, + @RequestParam("destSymbol") destSymbol: String, + @RequestParam("destAddress") destAddress: String, + @RequestParam("destNetwork") destNetwork: String?, + @RequestParam("destNote", required = false) destNote: String?, ): WithdrawResult { return withdrawService.requestWithdraw( - WithdrawCommand( - principal.name, - currency, - amount, - description, - transferRef, - destSymbol, - destAddress, - destNetwork, - destNote, - fee - ) + WithdrawCommand( + principal.name, + currency, + amount, + description, + transferRef, + destSymbol, + destAddress, + destNetwork, + destNote, + fee + ) ) } @PostMapping("/history/{uuid}") suspend fun getWithdrawTransactionsForUser( - @PathVariable("uuid") uuid: String, - @RequestBody request: TransactionRequest + @PathVariable("uuid") uuid: String, + @RequestBody request: TransactionRequest ): List { return withdrawService.findWithdrawHistory( - uuid, - request.coin, + uuid, + request.coin, request.startTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(request.startTime), ZoneId.systemDefault()) } @@ -114,27 +114,33 @@ class WithdrawController(private val withdrawService: WithdrawService) { request.endTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(request.endTime), ZoneId.systemDefault()) } ?: null, - request.limit!!, - request.offset!! + request.limit!!, + request.offset!!, + request.ascendingByTime ).map { WithdrawHistoryResponse( - it.withdrawId, - it.ownerUuid, - it.amount, - it.currency, - it.acceptedFee, - it.appliedFee, - it.destAmount, - it.destSymbol, - it.destAddress, - it.destNetwork, - it.destNote, - it.destTransactionRef, - it.statusReason, - it.status, - it.createDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), - it.acceptDate?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli(), + it.withdrawId, + it.ownerUuid, + it.amount, + it.currency, + it.acceptedFee, + it.appliedFee, + it.destAmount, + it.destSymbol, + it.destAddress, + it.destNetwork, + it.destNote, + it.destTransactionRef, + it.statusReason, + it.status, + it.createDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), + it.acceptDate?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli(), ) } } + + } + + + diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt index 66eccc78a..08b60a5b6 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt @@ -8,6 +8,7 @@ import co.nilin.opex.wallet.app.dto.ManualTransferRequest import co.nilin.opex.wallet.app.dto.ReservedTransferResponse import co.nilin.opex.wallet.app.dto.TransferRequest import co.nilin.opex.wallet.core.exc.NotEnoughBalanceException +import co.nilin.opex.wallet.core.inout.Deposit import co.nilin.opex.wallet.core.inout.TransferCommand import co.nilin.opex.wallet.core.inout.TransferResult import co.nilin.opex.wallet.core.model.Amount @@ -30,7 +31,8 @@ class TransferService( private val walletManager: WalletManager, private val walletOwnerManager: WalletOwnerManager, private val currencyGraph: co.nilin.opex.wallet.app.service.otc.GraphService, - private val reservedTransferManager: ReservedTransferManager + private val reservedTransferManager: ReservedTransferManager, + private val depositPersister: DepositPersister ) { @Autowired private lateinit var preferences: Preferences @@ -87,6 +89,7 @@ class TransferService( } } + @Transactional suspend fun deposit( symbol: String, @@ -94,9 +97,11 @@ class TransferService( receiverWalletType: String, amount: BigDecimal, description: String?, - transferRef: String? + transferRef: String?, + chain: String? ): TransferResult { - return _transfer( + + val tx = _transfer( symbol, "main", walletOwnerManager.systemUuid, @@ -109,7 +114,20 @@ class TransferService( null, symbol, amount + ) + depositPersister.persist(Deposit( + receiverUuid, + UUID.randomUUID().toString(), + symbol, + amount, + note = description, + transactionRef = transferRef, + status = "Done", + depositType = "On-chain", + network = chain + )) + return tx } suspend fun calculateDestinationAmount( @@ -271,29 +289,31 @@ class TransferService( suspend fun depositManually( symbol: String, receiverUuid: String, - senderUuid:String, + senderUuid: String, amount: BigDecimal, request: ManualTransferRequest ): TransferResult { logger.info("deposit manually: $senderUuid to $receiverUuid on $symbol at ${LocalDateTime.now()}") val systemUuid = "1" //todo customize error message - val senderLevel=walletOwnerManager.findWalletOwner(senderUuid)?.let {it.level }?:throw OpexException(OpexError.WalletOwnerNotFound) - val receiverLevel=walletOwnerManager.findWalletOwner(receiverUuid)?.let {it.level }?: walletOwnerManager.createWalletOwner( - receiverUuid, - "not set", - "1" - ).level + val senderLevel = walletOwnerManager.findWalletOwner(senderUuid)?.let { it.level } + ?: throw OpexException(OpexError.WalletOwnerNotFound) + val receiverLevel = walletOwnerManager.findWalletOwner(receiverUuid)?.let { it.level } + ?: walletOwnerManager.createWalletOwner( + receiverUuid, + "not set", + "1" + ).level - if ( senderLevel !in arrayListOf(preferences.admin.walletLevel,preferences.system.walletLevel)) + if (senderLevel !in arrayListOf(preferences.admin.walletLevel, preferences.system.walletLevel)) throw OpexException(OpexError.Forbidden) - if(senderLevel == preferences.system.walletLevel && receiverLevel !=preferences.admin.walletLevel) + if (senderLevel == preferences.system.walletLevel && receiverLevel != preferences.admin.walletLevel) throw OpexException(OpexError.Forbidden) // if (walletOwnerManager.findWalletOwner(receiverUuid)?.level !in arrayListOf(preferences.admin.walletLevel,preferences.system.walletLevel)) // throw OpexException(OpexError.Error) - return _transfer( + val tx = _transfer( symbol, "main", senderUuid, @@ -308,6 +328,17 @@ class TransferService( amount ) + depositPersister.persist(Deposit( + receiverUuid, + UUID.randomUUID().toString(), + symbol, + amount, + note = request.description, + transactionRef = request.ref, + status = "Done", + depositType = "System", + )) + return tx; } diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt new file mode 100644 index 000000000..e85d7d58c --- /dev/null +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt @@ -0,0 +1,25 @@ +package co.nilin.opex.wallet.core.inout + +import java.math.BigDecimal +import java.time.LocalDateTime + +data class Deposit( + var ownerUuid: String, + var depositUuid: String, + var currency: String, + var amount: BigDecimal, + var acceptedFee: BigDecimal?=null, + var appliedFee: BigDecimal?=null, + var sourceSymbol: String?=null, + var network: String?=null, + var sourceAddress: String?=null, + var transactionRef: String?=null, + var note: String?=null, + var status: String?=null, + var depositType:String?=null, + var createDate: LocalDateTime? = LocalDateTime.now(), +) + + + +data class Deposits(var deposits: List) \ No newline at end of file diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawResponse.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawResponse.kt index 6a7f3f6a6..4b5bc5808 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawResponse.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawResponse.kt @@ -23,5 +23,4 @@ class WithdrawResponse( val statusReason: String?, val status: String, val createDate: LocalDateTime = LocalDateTime.now(), - val acceptDate: LocalDateTime? = null -) \ No newline at end of file + val acceptDate: LocalDateTime? = null) \ No newline at end of file diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/service/WithdrawService.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/service/WithdrawService.kt index 381093f73..669b7f7f4 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/service/WithdrawService.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/service/WithdrawService.kt @@ -234,8 +234,10 @@ class WithdrawService( startTime: LocalDateTime?, endTime: LocalDateTime?, limit: Int, - offset: Int + offset: Int, + ascendingByTime:Boolean?=false ): List { - return withdrawPersister.findWithdrawHistory(uuid, coin, startTime, endTime, limit, offset) + return withdrawPersister.findWithdrawHistory(uuid, coin, startTime, endTime, limit, offset,ascendingByTime) } + } \ No newline at end of file diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/DepositPersister.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/DepositPersister.kt new file mode 100644 index 000000000..8d4a7787d --- /dev/null +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/DepositPersister.kt @@ -0,0 +1,27 @@ +package co.nilin.opex.wallet.core.spi + +import co.nilin.opex.wallet.core.inout.Deposit +import co.nilin.opex.wallet.core.inout.Deposits +import co.nilin.opex.wallet.core.inout.WithdrawResponse +import co.nilin.opex.wallet.core.model.Withdraw +import java.time.LocalDateTime + +interface DepositPersister { + + + + suspend fun persist(deposit: Deposit): Deposit + + + suspend fun findDepositHistory( + uuid: String, + coin: String?, + startTime: LocalDateTime?, + endTime: LocalDateTime?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? + ): Deposits + + +} \ No newline at end of file diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/TransactionManager.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/TransactionManager.kt index b5fccd76b..128b060cc 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/TransactionManager.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/TransactionManager.kt @@ -15,7 +15,8 @@ interface TransactionManager { startTime: LocalDateTime?, endTime: LocalDateTime?, limit: Int, - offset: Int + offset: Int, + ascendingByTime: Boolean?=false ): List suspend fun findWithdrawTransactions( diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/WithdrawPersister.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/WithdrawPersister.kt index cd1a747b5..0793c8124 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/WithdrawPersister.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/WithdrawPersister.kt @@ -48,6 +48,9 @@ interface WithdrawPersister { startTime: LocalDateTime?, endTime: LocalDateTime?, limit: Int, - offset: Int + offset: Int, + ascendingByTime: Boolean? ): List + + } \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/DepositRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/DepositRepository.kt new file mode 100644 index 000000000..308c9e5cd --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/DepositRepository.kt @@ -0,0 +1,58 @@ +package co.nilin.opex.wallet.ports.postgres.dao + +import co.nilin.opex.wallet.ports.postgres.model.DepositModel +import co.nilin.opex.wallet.ports.postgres.model.WithdrawModel +import kotlinx.coroutines.flow.Flow +import org.springframework.data.r2dbc.repository.Query +import org.springframework.data.repository.query.Param +import org.springframework.data.repository.reactive.ReactiveCrudRepository +import org.springframework.stereotype.Repository +import reactor.core.publisher.Mono +import java.time.LocalDateTime + +@Repository +interface DepositRepository : ReactiveCrudRepository { + + @Query( + """ + select * from deposits + where uuid = :uuid + and (:currency is null or currency = :currency) + and (:startTime is null or create_date > :startTime ) + and (:endTime is null or create_date <= :endTime) + order by create_date ASC + limit :limit + offset :offset + """ + ) + fun findDepositHistoryAsc( + @Param("uuid") uuid: String, + @Param("currency") currency: String?, + @Param("startTime") startTime: LocalDateTime?, + @Param("endTime") endTime: LocalDateTime?, + @Param("limit") limit: Int, + @Param("offset") offset: Int + ): Flow + + + @Query( + """ + select * from deposits + where uuid = :uuid + and (:currency is null or currency = :currency) + and (:startTime is null or create_date > :startTime ) + and (:endTime is null or create_date <= :endTime) + order by create_date DESC + limit :limit + offset :offset + """ + ) + fun findDepositHistoryDesc( + @Param("uuid") uuid: String, + @Param("currency") currency: String?, + @Param("startTime") startTime: LocalDateTime?, + @Param("endTime") endTime: LocalDateTime?, + @Param("limit") limit: Int, + @Param("offset") offset: Int + ): Flow +} \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/WithdrawRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/WithdrawRepository.kt index fccab370d..f071c6609 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/WithdrawRepository.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/WithdrawRepository.kt @@ -16,7 +16,7 @@ interface WithdrawRepository : ReactiveCrudRepository { fun findByWallet(@Param("wallet") wallet: Long): Flow @Query( - """ + """ select * from withdraws wth join wallet wm on wm.id = wth.wallet where wm.owner = :owner @@ -25,7 +25,7 @@ interface WithdrawRepository : ReactiveCrudRepository { fun findByOwner(@Param("owner") owner: Long): Flow @Query( - """ + """ select * from withdraws wth join wallet wm on wm.id = wth.wallet join wallet_owner wo on wm.owner = wo.id @@ -39,17 +39,17 @@ interface WithdrawRepository : ReactiveCrudRepository { """ ) fun findByCriteria( - @Param("owner") ownerUuid: String?, - @Param("withdraw_id") withdrawId: Long?, - @Param("currency") currency: String?, - @Param("dest_transaction_ref") destTxRef: String?, - @Param("dest_address") destAddress: String?, - @Param("no_status") noStatus: Boolean, - @Param("status") status: List? + @Param("owner") ownerUuid: String?, + @Param("withdraw_id") withdrawId: Long?, + @Param("currency") currency: String?, + @Param("dest_transaction_ref") destTxRef: String?, + @Param("dest_address") destAddress: String?, + @Param("no_status") noStatus: Boolean, + @Param("status") status: List? ): Flow @Query( - """ + """ select * from withdraws wth join wallet wm on wm.id = wth.wallet join wallet_owner wo on wm.owner = wo.id @@ -64,19 +64,19 @@ interface WithdrawRepository : ReactiveCrudRepository { """ ) fun findByCriteria( - @Param("owner") ownerUuid: String?, - @Param("withdraw_id") withdrawId: Long?, - @Param("currency") currency: String?, - @Param("dest_transaction_ref") destTxRef: String?, - @Param("dest_address") destAddress: String?, - @Param("no_status") noStatus: Boolean, - @Param("status") status: List?, - offset: Int, - size: Int + @Param("owner") ownerUuid: String?, + @Param("withdraw_id") withdrawId: Long?, + @Param("currency") currency: String?, + @Param("dest_transaction_ref") destTxRef: String?, + @Param("dest_address") destAddress: String?, + @Param("no_status") noStatus: Boolean, + @Param("status") status: List?, + offset: Int, + size: Int ): Flow @Query( - """ + """ select count(*) from withdraws wth join wallet wm on wm.id = wth.wallet join wallet_owner wo on wm.owner = wo.id @@ -89,53 +89,78 @@ interface WithdrawRepository : ReactiveCrudRepository { """ ) fun countByCriteria( - @Param("owner") ownerUuid: String?, - @Param("withdraw_id") withdrawId: Long?, - @Param("currency") currency: String?, - @Param("dest_transaction_ref") destTxRef: String?, - @Param("dest_address") destAddress: String?, - @Param("no_status") noStatus: Boolean, - @Param("status") status: List? + @Param("owner") ownerUuid: String?, + @Param("withdraw_id") withdrawId: Long?, + @Param("currency") currency: String?, + @Param("dest_transaction_ref") destTxRef: String?, + @Param("dest_address") destAddress: String?, + @Param("no_status") noStatus: Boolean, + @Param("status") status: List? ): Mono @Query("select * from withdraws where wallet = :wallet and transaction_id = :tx_id") fun findByWalletAndTransactionId( - @Param("wallet") wallet: Long, - @Param("tx_id") txId: String + @Param("wallet") wallet: Long, + @Param("tx_id") txId: String ): Mono @Query( - """ + """ select * from withdraws where uuid = :uuid - and currency = :currency + and (:currency is null or currency = :currency) and (:startTime is null or create_date > :startTime ) and (:endTime is null or create_date <= :endTime) + order by create_date ASC limit :limit + offset :offset """ ) - fun findWithdrawHistory( - @Param("uuid") uuid: String, - @Param("currency") currency: String, - @Param("startTime") startTime: LocalDateTime?, - @Param("endTime") endTime: LocalDateTime?, - @Param("limit") limit: Int, + fun findWithdrawHistoryAsc( + @Param("uuid") uuid: String, + @Param("currency") currency: String?, + @Param("startTime") startTime: LocalDateTime?, + @Param("endTime") endTime: LocalDateTime?, + @Param("limit") limit: Int, + @Param("offset") offset: Int ): Flow + @Query( - """ + """ select * from withdraws where uuid = :uuid + and (:currency is null or currency = :currency) and (:startTime is null or create_date > :startTime ) - and (:endTime is null or create_date <= :endTime) + and (:endTime is null or create_date <= :endTime) + order by create_date DESC limit :limit + offset :offset """ ) - fun findWithdrawHistory( - @Param("uuid") uuid: String, - @Param("startTime") startTime: LocalDateTime?, - @Param("endTime") endTime: LocalDateTime?, - @Param("limit") limit: Int, + fun findWithdrawHistoryDesc( + @Param("uuid") uuid: String, + @Param("currency") currency: String?, + @Param("startTime") startTime: LocalDateTime?, + @Param("endTime") endTime: LocalDateTime?, + @Param("limit") limit: Int, + @Param("offset") offset: Int ): Flow +// @Query( +// """ +// select * from withdraws +// where uuid = :uuid +// and (:startTime is null or create_date > :startTime ) +// and (:endTime is null or create_date <= :endTime) +// limit :limit +// """ +// ) +// fun findWithdrawHistory( +// @Param("uuid") uuid: String, +// @Param("startTime") startTime: LocalDateTime?, +// @Param("endTime") endTime: LocalDateTime?, +// @Param("limit") limit: Int, +// ): Flow + } \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/DepositPersisterImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/DepositPersisterImpl.kt new file mode 100644 index 000000000..b691805c3 --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/DepositPersisterImpl.kt @@ -0,0 +1,53 @@ +package co.nilin.opex.wallet.ports.postgres.impl + +import co.nilin.opex.wallet.core.inout.Deposit +import co.nilin.opex.wallet.core.inout.Deposits +import co.nilin.opex.wallet.core.inout.WithdrawResponse +import co.nilin.opex.wallet.core.model.Withdraw +import co.nilin.opex.wallet.core.spi.DepositPersister +import co.nilin.opex.wallet.core.spi.WithdrawPersister +import co.nilin.opex.wallet.ports.postgres.dao.DepositRepository +import co.nilin.opex.wallet.ports.postgres.util.toDto +import co.nilin.opex.wallet.ports.postgres.util.toModel +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.reactive.awaitFirst + +import org.springframework.stereotype.Service +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.* + +@Service +class DepositPersisterImpl( + private val depositRepository: DepositRepository, +) : DepositPersister { + + + override suspend fun persist(deposit: Deposit): Deposit { + val dm = depositRepository.save( + deposit.toModel() + ).awaitFirst() + + return dm.toDto() + } + + + override suspend fun findDepositHistory( + uuid: String, + coin: String?, + startTime: LocalDateTime?, + endTime: LocalDateTime?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? + ): Deposits { + val deposits = if (ascendingByTime == true) + depositRepository.findDepositHistoryAsc(uuid, coin, startTime, endTime, limit, offset) + else + depositRepository.findDepositHistoryDesc(uuid, coin, startTime, endTime, limit, offset) + return Deposits(deposits.map { it.toDto() }.toList()) + } + + +} \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TransactionManagerImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TransactionManagerImpl.kt index 9883f47b3..3ccf4d897 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TransactionManagerImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TransactionManagerImpl.kt @@ -16,35 +16,36 @@ import java.time.ZoneId @Service class TransactionManagerImpl( - private val transactionRepository: TransactionRepository, - private val objectMapper: ObjectMapper + private val transactionRepository: TransactionRepository, + private val objectMapper: ObjectMapper ) : TransactionManager { private val logger = LoggerFactory.getLogger(TransactionManagerImpl::class.java) override suspend fun save(transaction: Transaction): String { return transactionRepository.save( - TransactionModel( - null, - transaction.sourceWallet.id!!, - transaction.destWallet.id!!, - transaction.sourceAmount, - transaction.destAmount, - transaction.description, - transaction.transferRef, - transaction.transferCategory, - objectMapper.writeValueAsString(transaction.additionalData), - LocalDateTime.now() - ) + TransactionModel( + null, + transaction.sourceWallet.id!!, + transaction.destWallet.id!!, + transaction.sourceAmount, + transaction.destAmount, + transaction.description, + transaction.transferRef, + transaction.transferCategory, + objectMapper.writeValueAsString(transaction.additionalData), + LocalDateTime.now() + ) ).awaitSingle().id.toString() } override suspend fun findDepositTransactions( - uuid: String, - coin: String?, - startTime: LocalDateTime?, - endTime: LocalDateTime?, - limit: Int, - offset: Int + uuid: String, + coin: String?, + startTime: LocalDateTime?, + endTime: LocalDateTime?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? ): List { val transactions = if (coin != null) transactionRepository.findDepositTransactionsByUUIDAndCurrency(uuid, coin, startTime, endTime, limit) @@ -52,32 +53,32 @@ class TransactionManagerImpl( transactionRepository.findDepositTransactionsByUUID(uuid, startTime, endTime, limit) return transactions.collectList() - .awaitFirstOrElse { emptyList() } - .map { - TransactionHistory( - it.id, - it.currency, - it.wallet, - it.amount, - it.description, - it.ref, - it.date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), - it.category, - if (it.detail == null) emptyMap() else objectMapper.readValue( - it.detail, - Map::class.java - ) as Map?, - ) - } + .awaitFirstOrElse { emptyList() } + .map { + TransactionHistory( + it.id, + it.currency, + it.wallet, + it.amount, + it.description, + it.ref, + it.date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), + it.category, + if (it.detail == null) emptyMap() else objectMapper.readValue( + it.detail, + Map::class.java + ) as Map?, + ) + } } override suspend fun findWithdrawTransactions( - uuid: String, - coin: String?, - startTime: LocalDateTime?, - endTime: LocalDateTime?, - limit: Int, - offset: Int + uuid: String, + coin: String?, + startTime: LocalDateTime?, + endTime: LocalDateTime?, + limit: Int, + offset: Int ): List { val transactions = if (coin != null) transactionRepository.findWithdrawTransactionsByUUIDAndCurrency(uuid, coin, startTime, endTime, limit) @@ -85,62 +86,62 @@ class TransactionManagerImpl( transactionRepository.findWithdrawTransactionsByUUID(uuid, startTime, endTime, limit) return transactions.collectList() - .awaitFirstOrElse { emptyList() } - .map { - TransactionHistory( - it.id, - it.currency, - it.wallet, - it.amount, - it.description, - it.ref, - it.date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), - it.category, - if (it.detail == null) emptyMap() else objectMapper.readValue( - it.detail, - Map::class.java - ) as Map?, - ) - } + .awaitFirstOrElse { emptyList() } + .map { + TransactionHistory( + it.id, + it.currency, + it.wallet, + it.amount, + it.description, + it.ref, + it.date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), + it.category, + if (it.detail == null) emptyMap() else objectMapper.readValue( + it.detail, + Map::class.java + ) as Map?, + ) + } } override suspend fun findTransactions( - uuid: String, - coin: String?, - category: String?, - startTime: LocalDateTime?, - endTime: LocalDateTime?, - asc: Boolean, - limit: Int, - offset: Int + uuid: String, + coin: String?, + category: String?, + startTime: LocalDateTime?, + endTime: LocalDateTime?, + asc: Boolean, + limit: Int, + offset: Int ): List { val transactions = - if (asc) - transactionRepository.findTransactionsAsc(uuid, coin, category, startTime, endTime, limit, offset) - else - transactionRepository.findTransactionsDesc(uuid, coin, category, startTime, endTime, limit, offset) + if (asc) + transactionRepository.findTransactionsAsc(uuid, coin, category, startTime, endTime, limit, offset) + else + transactionRepository.findTransactionsDesc(uuid, coin, category, startTime, endTime, limit, offset) return transactions.collectList() - .awaitFirstOrElse { emptyList() } - .map { - TransactionWithDetailHistory( - it.id, - it.srcWallet, - it.destWallet, - it.senderUuid, - it.receiverUuid, - it.currency, - it.amount, - it.description, - it.ref, - it.date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), - it.category, - if (it.detail == null) emptyMap() else objectMapper.readValue( - it.detail, - Map::class.java - ) as Map?, - (it.senderUuid == uuid) && (it.senderUuid != it.receiverUuid) - ) - } + .awaitFirstOrElse { emptyList() } + .map { + TransactionWithDetailHistory( + it.id, + it.srcWallet, + it.destWallet, + it.senderUuid, + it.receiverUuid, + it.currency, + it.amount, + it.description, + it.ref, + it.date.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), + it.category, + if (it.detail == null) emptyMap() else objectMapper.readValue( + it.detail, + Map::class.java + ) as Map?, + (it.senderUuid == uuid) && (it.senderUuid != it.receiverUuid) + ) + } } } \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/WithdrawPersisterImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/WithdrawPersisterImpl.kt index 0370500f3..d58f618fa 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/WithdrawPersisterImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/WithdrawPersisterImpl.kt @@ -18,68 +18,47 @@ import java.util.* @Service class WithdrawPersisterImpl( - private val withdrawRepository: WithdrawRepository, - private val transactionRepository: TransactionRepository + private val withdrawRepository: WithdrawRepository, + private val transactionRepository: TransactionRepository ) : WithdrawPersister { override suspend fun findByCriteria( - ownerUuid: String?, - withdrawId: String?, - currency: String?, - destTxRef: String?, - destAddress: String?, - noStatus: Boolean, - status: List?, - offset: Int, - size: Int + ownerUuid: String?, + withdrawId: String?, + currency: String?, + destTxRef: String?, + destAddress: String?, + noStatus: Boolean, + status: List?, + offset: Int, + size: Int ): List { return withdrawRepository - .findByCriteria( - ownerUuid, - withdrawId?.toLong(), - currency, - destTxRef, - destAddress, - noStatus, - status, - offset, - size - ) - .map { it.asWithdrawResponse() } - .toList() + .findByCriteria( + ownerUuid, + withdrawId?.toLong(), + currency, + destTxRef, + destAddress, + noStatus, + status, + offset, + size + ) + .map { it.asWithdrawResponse() } + .toList() } override suspend fun countByCriteria( - ownerUuid: String?, - withdrawId: String?, - currency: String?, - destTxRef: String?, - destAddress: String?, - noStatus: Boolean, - status: List? + ownerUuid: String?, + withdrawId: String?, + currency: String?, + destTxRef: String?, + destAddress: String?, + noStatus: Boolean, + status: List? ): Long { return withdrawRepository.countByCriteria( - ownerUuid, - withdrawId?.toLong(), - currency, - destTxRef, - destAddress, - noStatus, - status - ).awaitFirstOrElse { 0 } - } - - override suspend fun findByCriteria( - ownerUuid: String?, - withdrawId: String?, - currency: String?, - destTxRef: String?, - destAddress: String?, - noStatus: Boolean, - status: List? - ): List { - return withdrawRepository - .findByCriteria( ownerUuid, withdrawId?.toLong(), currency, @@ -87,34 +66,55 @@ class WithdrawPersisterImpl( destAddress, noStatus, status - ) - .map { it.asWithdrawResponse() } - .toList() + ).awaitFirstOrElse { 0 } + } + + override suspend fun findByCriteria( + ownerUuid: String?, + withdrawId: String?, + currency: String?, + destTxRef: String?, + destAddress: String?, + noStatus: Boolean, + status: List? + ): List { + return withdrawRepository + .findByCriteria( + ownerUuid, + withdrawId?.toLong(), + currency, + destTxRef, + destAddress, + noStatus, + status + ) + .map { it.asWithdrawResponse() } + .toList() } override suspend fun persist(withdraw: Withdraw): Withdraw { val wm = withdrawRepository.save( - WithdrawModel( - withdraw.withdrawId, - withdraw.ownerUuid, - withdraw.currency, - withdraw.wallet, - withdraw.amount, - withdraw.requestTransaction, - withdraw.finalizedTransaction, - withdraw.acceptedFee, - withdraw.appliedFee, - withdraw.destAmount, - withdraw.destSymbol, - withdraw.destNetwork, - withdraw.destAddress, - withdraw.destNote, - withdraw.destTransactionRef, - withdraw.statusReason, - withdraw.status, - withdraw.createDate, - withdraw.acceptDate - ) + WithdrawModel( + withdraw.withdrawId, + withdraw.ownerUuid, + withdraw.currency, + withdraw.wallet, + withdraw.amount, + withdraw.requestTransaction, + withdraw.finalizedTransaction, + withdraw.acceptedFee, + withdraw.appliedFee, + withdraw.destAmount, + withdraw.destSymbol, + withdraw.destNetwork, + withdraw.destAddress, + withdraw.destNote, + withdraw.destTransactionRef, + withdraw.statusReason, + withdraw.status, + withdraw.createDate, + withdraw.acceptDate + ) ).awaitFirst() return wm.asWithdraw() @@ -122,25 +122,27 @@ class WithdrawPersisterImpl( override suspend fun findById(withdrawId: String): Withdraw? { return withdrawRepository.findById(withdrawId) - .map { it.asWithdraw() } - .awaitFirstOrNull() + .map { it.asWithdraw() } + .awaitFirstOrNull() } override suspend fun findWithdrawHistory( - uuid: String, - coin: String?, - startTime: LocalDateTime?, - endTime: LocalDateTime?, - limit: Int, - offset: Int + uuid: String, + coin: String?, + startTime: LocalDateTime?, + endTime: LocalDateTime?, + limit: Int, + offset: Int, + ascendingByTime: Boolean? ): List { - val withdraws = if (coin == null) - withdrawRepository.findWithdrawHistory(uuid, startTime, endTime, limit) + val withdraws = if (ascendingByTime == true) + withdrawRepository.findWithdrawHistoryAsc(uuid, coin, startTime, endTime, limit, offset) else - withdrawRepository.findWithdrawHistory(uuid, coin, startTime, endTime, limit) + withdrawRepository.findWithdrawHistoryDesc(uuid, coin, startTime, endTime, limit, offset) return withdraws.map { it.asWithdraw() }.toList() } + private suspend fun WithdrawModel.asWithdrawResponse(): WithdrawResponse { val reqTx = transactionRepository.findById(requestTransaction.toLong()).awaitFirst() val finalTx = if (finalizedTransaction == null) @@ -148,49 +150,50 @@ class WithdrawPersisterImpl( else transactionRepository.findById(finalizedTransaction.toLong()).awaitFirstOrNull() return WithdrawResponse( - id!!, - ownerUuid, - Date.from(reqTx.txDate.atZone(ZoneId.systemDefault()).toInstant()), - if (finalTx == null) null else Date.from(finalTx.txDate.atZone(ZoneId.systemDefault()).toInstant()), - reqTx.id.toString(), - finalTx?.id.toString(), - acceptedFee, - appliedFee, - amount, - destAmount, - destSymbol, - destAddress, - destNetwork, - destNote, - destTransactionRef, - statusReason, - status, - createDate, - acceptDate + id!!, + ownerUuid, + Date.from(reqTx.txDate.atZone(ZoneId.systemDefault()).toInstant()), + if (finalTx == null) null else Date.from(finalTx.txDate.atZone(ZoneId.systemDefault()).toInstant()), + reqTx.id.toString(), + finalTx?.id.toString(), + acceptedFee, + appliedFee, + amount, + destAmount, + destSymbol, + destAddress, + destNetwork, + destNote, + destTransactionRef, + statusReason, + status, + createDate, + acceptDate ) } + private fun WithdrawModel.asWithdraw(): Withdraw { return Withdraw( - id, - ownerUuid, - currency, - wallet, - amount, - requestTransaction, - finalizedTransaction, - acceptedFee, - appliedFee, - destAmount, - destSymbol, - destAddress, - destNetwork, - destNote, - destTransactionRef, - statusReason, - status, - createDate, - acceptDate + id, + ownerUuid, + currency, + wallet, + amount, + requestTransaction, + finalizedTransaction, + acceptedFee, + appliedFee, + destAmount, + destSymbol, + destAddress, + destNetwork, + destNote, + destTransactionRef, + statusReason, + status, + createDate, + acceptDate ) } } \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/DepositModel.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/DepositModel.kt new file mode 100644 index 000000000..7bd0cc445 --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/DepositModel.kt @@ -0,0 +1,25 @@ +package co.nilin.opex.wallet.ports.postgres.model + +import org.springframework.data.annotation.Id +import org.springframework.data.relational.core.mapping.Column +import org.springframework.data.relational.core.mapping.Table +import java.math.BigDecimal +import java.time.LocalDateTime + +@Table("deposits") +data class DepositModel(@Id var id: Long?, + @Column("uuid") val ownerUuid: String, + @Column("duid") val depositUuid: String, + @Column("currency") val currency: String, + @Column("amount") val amount: BigDecimal, + @Column("accepted_fee") val acceptedFee: BigDecimal?, + @Column("applied_fee") val appliedFee: BigDecimal?, + @Column("source_symbol") val sourceSymbol: String?, + @Column("network") val network: String?, + @Column("source_address") val sourceAddress: String?, + @Column("note") var note: String?, + @Column("transaction_ref") var transactionRef:String?, + @Column("status") var status: String?, + @Column("deposit_type") var depositType: String?, + @Column("create_date") val createDate: LocalDateTime? = LocalDateTime.now() +) diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt new file mode 100644 index 000000000..e32e5f195 --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt @@ -0,0 +1,44 @@ +package co.nilin.opex.wallet.ports.postgres.util + +import co.nilin.opex.wallet.core.inout.Deposit +import co.nilin.opex.wallet.ports.postgres.model.DepositModel + + + + fun Deposit.toModel():DepositModel{ + return DepositModel(null, + ownerUuid, + depositUuid, + currency, + amount, + acceptedFee, + appliedFee, + sourceSymbol, + network, + sourceAddress, + note, + transactionRef, + status, + depositType, + createDate) + } + + + +fun DepositModel.toDto():Deposit{ + return Deposit( + ownerUuid, + depositUuid, + currency, + amount, + acceptedFee, + appliedFee, + sourceSymbol, + network, + sourceAddress, + note, + transactionRef, + status, + depositType, + createDate) +} \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/resources/schema.sql b/wallet/wallet-ports/wallet-persister-postgres/src/main/resources/schema.sql index 1ef179f8a..fedff6470 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/resources/schema.sql +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/resources/schema.sql @@ -177,4 +177,23 @@ CREATE TABLE IF NOT EXISTS wallet_stat_exclusion ( id SERIAL PRIMARY KEY, wallet_id INTEGER NOT NULL UNIQUE REFERENCES wallet (id) -) +); + + +CREATE TABLE IF NOT EXISTS deposits ( + id SERIAL PRIMARY KEY, + uuid VARCHAR(255) NOT NULL, + duid VARCHAR(255) NOT NULL, + currency VARCHAR(255) NOT NULL REFERENCES currency (symbol), + amount DECIMAL NOT NULL, -- Use a numeric type for decimal values + accepted_fee DECIMAL, + applied_fee DECIMAL, + source_symbol VARCHAR(255), + network VARCHAR(255), + source_address VARCHAR(255), + note TEXT, + transaction_ref VARCHAR(255), + status VARCHAR(255), + deposit_type VARCHAR(255), + create_date TIMESTAMP +); \ No newline at end of file From 0d9f1d01a02d270915e67ca3f5e7ffce05400afb Mon Sep 17 00:00:00 2001 From: Fatemeh imani <46007372+fatemeh-i@users.noreply.github.com> Date: Sat, 29 Jun 2024 15:11:38 +0330 Subject: [PATCH 2/9] Handle "self-trade" category in fetching trades' transactions (#452) * change tx history query to have better performance * update trx security filter * fix reference of currencies comparation ( object -> symbol) * seprate withdraw categories based on steps, enable unlimited report history * add withdraw filed to tx history resp * fix withdraw settelment filed to tx history resp * expose chains information service * change permission of getChainsInfo * fix query syntax * start developing new service to fetch tx history * fetch tx of trades table to have new tx history service * Save deposit tx seprately * develop new service to fetch deposit history * handle self-trade in fetching transactions * fix query bug * fix query bug --- .../app/controller/UserDataController.kt | 2 +- .../ports/postgres/dao/TradeRepository.kt | 57 +++++++++++++++++-- .../app/controller/DepositController.kt | 2 +- .../wallet/app/service/TransferService.kt | 9 ++- 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt index e95fbe9ea..d50164baa 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt @@ -45,7 +45,7 @@ class UserDataController(private val userQueryHandler: UserQueryHandler) { suspend fun getTxOfTrades(@PathVariable user: String, @RequestBody transactionRequest: TransactionRequest, @CurrentSecurityContext securityContext: SecurityContext): TxOfTrades? { - if (securityContext != null && securityContext.authentication.name != user) + if (securityContext.authentication.name != user) throw OpexError.Forbidden.exception() return userQueryHandler.txOfTrades(transactionRequest.apply { owner = user }) } diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt index a5ab2053a..19e0d1fdc 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt @@ -387,8 +387,33 @@ interface TradeRepository : ReactiveCrudRepository { WHERE (t.maker_uuid = :user OR t.taker_uuid = :user) and (:startDate is null or trade_date >=:startDate) and (:endDate is null or trade_date <=:endDate) - order by trade_date DESC offset :offset limit :limit """) - fun findTxOfTradesDesc(user: String, startDate: LocalDateTime?, endDate: LocalDateTime?, offset: Int?, limit: Int?): Flux + + union + + select t.trade_date As create_date, + t.matched_quantity AS volume, + t.matched_price AS matched_price, + CASE + WHEN t.taker_uuid = :user THEN t.taker_commission + WHEN t.maker_uuid = :user THEN t.maker_commission + END AS fee, + CASE + WHEN t.taker_uuid = :user THEN o2.side + WHEN t.maker_uuid = :user THEN o1.side + END AS side, + t.matched_price * t.matched_quantity as transaction_price, + substring(t.symbol, 0, position('_' in t.symbol) ) AS symbol + FROM trades t + INNER JOIN orders o1 ON t.maker_ouid = o1.ouid + LEFT JOIN orders o2 ON t.taker_ouid = o2.ouid + WHERE (t.maker_uuid = :user OR t.taker_uuid = :user) + and (:startDate is null or trade_date >=:startDate) + and (:endDate is null or trade_date <=:endDate) + + order by create_date ASC offset :offset limit :limit """) + + fun findTxOfTradesAsc(user: String, startDate: LocalDateTime?, endDate: LocalDateTime?, offset: Int?, limit: Int?): Flux + @Query(""" select t.trade_date As create_date, @@ -410,8 +435,32 @@ interface TradeRepository : ReactiveCrudRepository { WHERE (t.maker_uuid = :user OR t.taker_uuid = :user) and (:startDate is null or trade_date >=:startDate) and (:endDate is null or trade_date <=:endDate) - order by trade_date ASC offset :offset limit :limit """) - fun findTxOfTradesAsc(user: String, startDate: LocalDateTime?, endDate: LocalDateTime?, offset: Int?, limit: Int?): Flux + + union + + select t.trade_date As create_date, + t.matched_quantity AS volume, + t.matched_price AS matched_price, + CASE + WHEN t.taker_uuid = :user THEN t.taker_commission + WHEN t.maker_uuid = :user THEN t.maker_commission + END AS fee, + CASE + WHEN t.taker_uuid = :user THEN o2.side + WHEN t.maker_uuid = :user THEN o1.side + END AS side, + t.matched_price * t.matched_quantity as transaction_price, + substring(t.symbol, 0, position('_' in t.symbol) ) AS symbol + FROM trades t + INNER JOIN orders o1 ON t.maker_ouid = o1.ouid + LEFT JOIN orders o2 ON t.taker_ouid = o2.ouid + WHERE (t.maker_uuid = :user OR t.taker_uuid = :user) + and (:startDate is null or trade_date >=:startDate) + and (:endDate is null or trade_date <=:endDate) + + order by create_date DESC offset :offset limit :limit """) + + fun findTxOfTradesDesc(user: String, startDate: LocalDateTime?, endDate: LocalDateTime?, offset: Int?, limit: Int?): Flux } \ No newline at end of file diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt index 1ea6d5c58..eb6eee4fb 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt @@ -32,7 +32,7 @@ class DepositController(private val depositPersister: DepositPersister, @RequestBody request: TransactionRequest, @CurrentSecurityContext securityContext: SecurityContext ): Deposits { - if (securityContext!=null && securityContext.authentication.name != uuid) + if (securityContext.authentication.name != uuid) throw OpexError.Forbidden.exception() return Deposits(depositPersister.findDepositHistory( uuid, diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt index 08b60a5b6..e0df74834 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt @@ -298,7 +298,7 @@ class TransferService( //todo customize error message val senderLevel = walletOwnerManager.findWalletOwner(senderUuid)?.let { it.level } ?: throw OpexException(OpexError.WalletOwnerNotFound) - val receiverLevel = walletOwnerManager.findWalletOwner(receiverUuid)?.let { it.level } + walletOwnerManager.findWalletOwner(receiverUuid)?.let { it.level } ?: walletOwnerManager.createWalletOwner( receiverUuid, "not set", @@ -308,8 +308,11 @@ class TransferService( if (senderLevel !in arrayListOf(preferences.admin.walletLevel, preferences.system.walletLevel)) throw OpexException(OpexError.Forbidden) - if (senderLevel == preferences.system.walletLevel && receiverLevel != preferences.admin.walletLevel) - throw OpexException(OpexError.Forbidden) + //todo need to fix conflict between otc and exchange + +// if (senderLevel == preferences.system.walletLevel && receiverLevel != preferences.admin.walletLevel) +// throw OpexException(OpexError.Forbidden) + // if (walletOwnerManager.findWalletOwner(receiverUuid)?.level !in arrayListOf(preferences.admin.walletLevel,preferences.system.walletLevel)) // throw OpexException(OpexError.Error) From 6eb5adccee49f761d01aadd8a3203ff8bd2cf901 Mon Sep 17 00:00:00 2001 From: Fatemeh imani <46007372+fatemeh-i@users.noreply.github.com> Date: Sat, 29 Jun 2024 16:23:51 +0330 Subject: [PATCH 3/9] Change in logic of manual deposit (#453) * change tx history query to have better performance * update trx security filter * fix reference of currencies comparation ( object -> symbol) * seprate withdraw categories based on steps, enable unlimited report history * add withdraw filed to tx history resp * fix withdraw settelment filed to tx history resp * expose chains information service * change permission of getChainsInfo * fix query syntax * start developing new service to fetch tx history * fetch tx of trades table to have new tx history service * Save deposit tx seprately * develop new service to fetch deposit history * handle self-trade in fetching transactions * fix query bug * fix query bug * change in logic of manual deposit --- .../binance/controller/WalletController.kt | 45 +++++++++++++++++++ .../api/ports/binance/data/WithDrawRequest.kt | 18 ++++++++ .../ports/postgres/dao/OrderRepository.kt | 1 + .../ports/postgres/dao/TradeRepository.kt | 1 + .../opex/wallet/app/config/SecurityConfig.kt | 4 +- .../wallet/app/service/TransferService.kt | 6 ++- 6 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/WithDrawRequest.kt diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt index 2209814a0..9c2a297a8 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt @@ -11,6 +11,7 @@ import co.nilin.opex.common.utils.Interval import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import java.math.BigDecimal @@ -150,6 +151,50 @@ class WalletController( } + @GetMapping("/v2/capital/withdraw/history") + suspend fun getWithdrawTransactionsV2( + @RequestBody withdrawRequest:WithDrawRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): List { + val validLimit = withdrawRequest.limit ?: 1000 + val response = walletProxy.getWithdrawTransactions( + securityContext.jwtAuthentication().name, + securityContext.jwtAuthentication().tokenValue(), + withdrawRequest.coin, + withdrawRequest.startTime ?: null, + withdrawRequest.endTime ?: null, + if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, + withdrawRequest.offset ?: 0, + withdrawRequest.ascendingByTime + ) + return response.map { + val status = when (it.status) { + "CREATED" -> 0 + "DONE" -> 1 + "REJECTED" -> 2 + else -> -1 + } + + WithdrawResponse( + it.destAddress ?: "0x0", + it.amount, + LocalDateTime.ofInstant(Instant.ofEpochMilli(it.createDate), ZoneId.systemDefault()) + .toString() + .replace("T", " "), + it.destSymbol ?: "", + it.withdrawId?.toString() ?: "", + "", + it.destNetwork ?: "", + 1, + status, + it.appliedFee.toString(), + 3, + it.destTransactionRef ?: it.withdrawId.toString(), + if (status == 1 && it.acceptDate != null) it.acceptDate!! else it.createDate + ) + } + } + @GetMapping("/v1/asset/tradeFee") suspend fun getPairFees( @RequestParam(required = false) diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/WithDrawRequest.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/WithDrawRequest.kt new file mode 100644 index 000000000..4b32b5080 --- /dev/null +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/WithDrawRequest.kt @@ -0,0 +1,18 @@ +package co.nilin.opex.api.ports.binance.data + +import com.fasterxml.jackson.annotation.JsonProperty +import org.springframework.web.bind.annotation.RequestParam + +data class WithDrawRequest( + var coin: String?, + var withdrawOrderId: String?, + @JsonProperty("status") + var withdrawStatus: Int?, + var offset: Int?, + var limit: Int?, + var startTime: Long?, + var endTime: Long?, + var ascendingByTime: Boolean? = false, + var recvWindow: Long?, //The value cannot be greater than 60000 + var timestamp: Long, +) diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/OrderRepository.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/OrderRepository.kt index 8b060034f..164984152 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/OrderRepository.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/OrderRepository.kt @@ -62,6 +62,7 @@ interface OrderRepository : ReactiveCrudRepository { and (:symbol is null or symbol = :symbol) and (:startTime is null or update_date >= :startTime) and (:endTime is null or update_date < :endTime) + order by update_date DESC limit :limit """ ) diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt index 19e0d1fdc..e7e65c16f 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/dao/TradeRepository.kt @@ -35,6 +35,7 @@ interface TradeRepository : ReactiveCrudRepository { and (:symbol is null or symbol = :symbol) and (:startTime is null or trade_date >= :startTime) and (:endTime is null or trade_date < :endTime) + order by trade_date DESC limit :limit """ ) diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt index 89401d27e..b89929255 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt @@ -30,8 +30,8 @@ class SecurityConfig(private val webClient: WebClient) { .pathMatchers("/balanceOf/**").hasAuthority("SCOPE_trust") .pathMatchers("/owner/**").hasAuthority("SCOPE_trust") .pathMatchers("/withdraw").hasAuthority("SCOPE_trust") - .pathMatchers("/deposit/manually").hasRole("SCOPE_trust", "admin_finance") - .pathMatchers("/deposit/**").hasAuthority("SCOPE_trust") + .pathMatchers("/v1/deposit/manually/**").hasRole("SCOPE_trust", "admin_finance") + .pathMatchers("/v1/deposit/**").hasAuthority("SCOPE_trust") .pathMatchers("/withdraw/**").hasAuthority("SCOPE_trust") .pathMatchers("/transaction/**").hasAuthority("SCOPE_trust") .pathMatchers("/admin/**").hasRole("SCOPE_trust", "admin_finance") diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt index e0df74834..d61855dd5 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/TransferService.kt @@ -305,8 +305,8 @@ class TransferService( "1" ).level - if (senderLevel !in arrayListOf(preferences.admin.walletLevel, preferences.system.walletLevel)) - throw OpexException(OpexError.Forbidden) +// if (senderLevel !in arrayListOf(preferences.admin.walletLevel, preferences.system.walletLevel)) +// throw OpexException(OpexError.Forbidden) //todo need to fix conflict between otc and exchange @@ -314,8 +314,10 @@ class TransferService( // throw OpexException(OpexError.Forbidden) + // if (walletOwnerManager.findWalletOwner(receiverUuid)?.level !in arrayListOf(preferences.admin.walletLevel,preferences.system.walletLevel)) // throw OpexException(OpexError.Error) + val tx = _transfer( symbol, "main", From ed0d245efba1970d509e356e8312589aac2b6046 Mon Sep 17 00:00:00 2001 From: Fatemeh imani <46007372+fatemeh-i@users.noreply.github.com> Date: Sat, 29 Jun 2024 17:27:47 +0330 Subject: [PATCH 4/9] Change method type in fetching withdraws' history (#454) * change tx history query to have better performance * update trx security filter * fix reference of currencies comparation ( object -> symbol) * seprate withdraw categories based on steps, enable unlimited report history * add withdraw filed to tx history resp * fix withdraw settelment filed to tx history resp * expose chains information service * change permission of getChainsInfo * fix query syntax * start developing new service to fetch tx history * fetch tx of trades table to have new tx history service * Save deposit tx seprately * develop new service to fetch deposit history * handle self-trade in fetching transactions * fix query bug * fix query bug * change in logic of manual deposit * change method type in fetching withdraw history * change method type in fetching trades' tx history --- .../opex/api/ports/binance/controller/WalletController.kt | 3 ++- .../co/nilin/opex/market/app/controller/UserDataController.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt index 9c2a297a8..878918254 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt @@ -11,6 +11,7 @@ import co.nilin.opex.common.utils.Interval import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @@ -151,7 +152,7 @@ class WalletController( } - @GetMapping("/v2/capital/withdraw/history") + @PostMapping("/v2/capital/withdraw/history") suspend fun getWithdrawTransactionsV2( @RequestBody withdrawRequest:WithDrawRequest, @CurrentSecurityContext securityContext: SecurityContext diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt index d50164baa..2a023f940 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt @@ -41,7 +41,7 @@ class UserDataController(private val userQueryHandler: UserQueryHandler) { return userQueryHandler.allTrades(uuid, request) } - @GetMapping("/tx/{user}/history") + @PostMapping("/tx/{user}/history") suspend fun getTxOfTrades(@PathVariable user: String, @RequestBody transactionRequest: TransactionRequest, @CurrentSecurityContext securityContext: SecurityContext): TxOfTrades? { From 13f33f0e548dc09a8ef9aca2134259e23c0ec80e Mon Sep 17 00:00:00 2001 From: Fatemeh imani <46007372+fatemeh-i@users.noreply.github.com> Date: Sat, 29 Jun 2024 19:28:38 +0330 Subject: [PATCH 5/9] Change date format in some services (#455) * change tx history query to have better performance * update trx security filter * fix reference of currencies comparation ( object -> symbol) * seprate withdraw categories based on steps, enable unlimited report history * add withdraw filed to tx history resp * fix withdraw settelment filed to tx history resp * expose chains information service * change permission of getChainsInfo * fix query syntax * start developing new service to fetch tx history * fetch tx of trades table to have new tx history service * Save deposit tx seprately * develop new service to fetch deposit history * handle self-trade in fetching transactions * fix query bug * fix query bug * change in logic of manual deposit * change method type in fetching withdraw history * change method type in fetching trades' tx history * Change date format in some services --- .../app/controller/UserDataController.kt | 2 +- .../opex/market/core/inout/Transaction.kt | 2 +- .../market/core/inout/TransactionResponse.kt | 19 ++++++++ .../opex/market/core/spi/UserQueryHandler.kt | 2 +- .../postgres/impl/UserQueryHandlerImpl.kt | 11 ++--- .../market/ports/postgres/util/Convertor.kt | 21 +++++++++ .../app/controller/DepositController.kt | 9 +--- .../nilin/opex/wallet/core/inout/Deposit.kt | 3 +- .../wallet/ports/postgres/util/Convertor.kt | 43 ++++++++++--------- 9 files changed, 75 insertions(+), 37 deletions(-) create mode 100644 market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionResponse.kt create mode 100644 market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/Convertor.kt diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt index 2a023f940..fe3cf5cd5 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt @@ -44,7 +44,7 @@ class UserDataController(private val userQueryHandler: UserQueryHandler) { @PostMapping("/tx/{user}/history") suspend fun getTxOfTrades(@PathVariable user: String, @RequestBody transactionRequest: TransactionRequest, - @CurrentSecurityContext securityContext: SecurityContext): TxOfTrades? { + @CurrentSecurityContext securityContext: SecurityContext): TransactionResponse? { if (securityContext.authentication.name != user) throw OpexError.Forbidden.exception() return userQueryHandler.txOfTrades(transactionRequest.apply { owner = user }) diff --git a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt index 267387369..39b85d1b9 100644 --- a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt +++ b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt @@ -14,4 +14,4 @@ data class Transaction( var user: String?=null ) -data class TxOfTrades(var transaction:List?) \ No newline at end of file +data class TxOfTrades(var transactions:List?) \ No newline at end of file diff --git a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionResponse.kt b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionResponse.kt new file mode 100644 index 000000000..bc50f7f80 --- /dev/null +++ b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionResponse.kt @@ -0,0 +1,19 @@ +package co.nilin.opex.market.core.inout + +import java.math.BigDecimal +import java.time.LocalDateTime +import java.util.Date + + +data class TransactionDto( + var createDate: Date, + var volume: BigDecimal, + val transactionPrice: BigDecimal, + var matchedPrice: BigDecimal, + var side: String, + var symbol: String, + var fee: BigDecimal, + var user: String?=null +) + +data class TransactionResponse(var transactions:List?) \ No newline at end of file diff --git a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt index a168de797..1a7d097d9 100644 --- a/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt +++ b/market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/UserQueryHandler.kt @@ -15,6 +15,6 @@ interface UserQueryHandler { suspend fun allTrades(uuid: String, request: TradeRequest): List - suspend fun txOfTrades(transactionRequest: TransactionRequest): TxOfTrades? + suspend fun txOfTrades(transactionRequest: TransactionRequest): TransactionResponse? } \ No newline at end of file diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt index 0a6ea4ded..bf2c934d6 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/UserQueryHandlerImpl.kt @@ -7,6 +7,7 @@ import co.nilin.opex.market.ports.postgres.dao.OrderRepository import co.nilin.opex.market.ports.postgres.dao.OrderStatusRepository import co.nilin.opex.market.ports.postgres.dao.TradeRepository import co.nilin.opex.market.ports.postgres.util.asOrderDTO +import co.nilin.opex.market.ports.postgres.util.toDto import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList @@ -101,23 +102,23 @@ class UserQueryHandlerImpl( }.toList() } - override suspend fun txOfTrades(transactionRequest: TransactionRequest): TxOfTrades? { + override suspend fun txOfTrades(transactionRequest: TransactionRequest): TransactionResponse? { if (transactionRequest.ascendingByTime == true) - return TxOfTrades(tradeRepository.findTxOfTradesAsc(transactionRequest.owner!!, + return TransactionResponse(tradeRepository.findTxOfTradesAsc(transactionRequest.owner!!, transactionRequest.startTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.startTime!!), ZoneId.systemDefault()) } ?: null, transactionRequest.endTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.endTime!!), ZoneId.systemDefault()) } ?: null, transactionRequest.offset, transactionRequest.limit - ).collectList()?.awaitFirstOrNull()) + ).map { it.toDto() }.collectList()?.awaitFirstOrNull()) else - return TxOfTrades(tradeRepository.findTxOfTradesDesc(transactionRequest.owner!!, + return TransactionResponse(tradeRepository.findTxOfTradesDesc(transactionRequest.owner!!, transactionRequest.startTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.startTime!!), ZoneId.systemDefault()) } ?: null, transactionRequest.endTime?.let { LocalDateTime.ofInstant(Instant.ofEpochMilli(transactionRequest.endTime!!), ZoneId.systemDefault()) } ?: null, transactionRequest.offset, transactionRequest.limit - ).collectList()?.awaitFirstOrNull()) + ).map { it.toDto() }.collectList()?.awaitFirstOrNull()) } } \ No newline at end of file diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/Convertor.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/Convertor.kt new file mode 100644 index 000000000..ddb42a1b9 --- /dev/null +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/Convertor.kt @@ -0,0 +1,21 @@ +package co.nilin.opex.market.ports.postgres.util + +import co.nilin.opex.market.core.inout.Transaction +import co.nilin.opex.market.core.inout.TransactionDto +import java.math.BigDecimal +import java.time.ZoneId +import java.util.* + + + fun Transaction.toDto(): TransactionDto { + return TransactionDto(createDate = Date.from(createDate.atZone(ZoneId.systemDefault()).toInstant()), + volume, + transactionPrice, + matchedPrice, + side, + symbol, + fee, + user) + + + } diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt index eb6eee4fb..2e8ac50b6 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt @@ -34,7 +34,7 @@ class DepositController(private val depositPersister: DepositPersister, ): Deposits { if (securityContext.authentication.name != uuid) throw OpexError.Forbidden.exception() - return Deposits(depositPersister.findDepositHistory( + return depositPersister.findDepositHistory( uuid, request.coin, request.startTime?.let { @@ -47,15 +47,10 @@ class DepositController(private val depositPersister: DepositPersister, request.limit!!, request.offset!!, request.ascendingByTime - ).deposits.map { - it.apply { it.createDate?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli() } - - }) + ) } - - @PostMapping("/manually/{amount}_{symbol}/{receiverUuid}") @ApiResponse( message = "OK", diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt index e85d7d58c..9ff5d86f6 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/Deposit.kt @@ -2,6 +2,7 @@ package co.nilin.opex.wallet.core.inout import java.math.BigDecimal import java.time.LocalDateTime +import java.util.* data class Deposit( var ownerUuid: String, @@ -17,7 +18,7 @@ data class Deposit( var note: String?=null, var status: String?=null, var depositType:String?=null, - var createDate: LocalDateTime? = LocalDateTime.now(), + var createDate: Date?=Date(), ) diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt index e32e5f195..d17eb89ba 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt @@ -2,30 +2,30 @@ package co.nilin.opex.wallet.ports.postgres.util import co.nilin.opex.wallet.core.inout.Deposit import co.nilin.opex.wallet.ports.postgres.model.DepositModel +import java.time.ZoneId +import java.util.* - - fun Deposit.toModel():DepositModel{ - return DepositModel(null, - ownerUuid, - depositUuid, - currency, - amount, - acceptedFee, - appliedFee, - sourceSymbol, - network, - sourceAddress, - note, - transactionRef, - status, - depositType, - createDate) - } - +fun Deposit.toModel(): DepositModel { + return DepositModel(null, + ownerUuid, + depositUuid, + currency, + amount, + acceptedFee, + appliedFee, + sourceSymbol, + network, + sourceAddress, + note, + transactionRef, + status, + depositType, + createDate?.toInstant()?.atZone(ZoneId.systemDefault())?.toLocalDateTime()) +} -fun DepositModel.toDto():Deposit{ +fun DepositModel.toDto(): Deposit { return Deposit( ownerUuid, depositUuid, @@ -40,5 +40,6 @@ fun DepositModel.toDto():Deposit{ transactionRef, status, depositType, - createDate) + Date.from(createDate?.atZone(ZoneId.systemDefault())?.toInstant()) + ) } \ No newline at end of file From 773c9cc8e7df309b182ec0fff29de79c32b74047 Mon Sep 17 00:00:00 2001 From: Fatemeh imani <46007372+fatemeh-i@users.noreply.github.com> Date: Sat, 29 Jun 2024 21:13:59 +0330 Subject: [PATCH 6/9] Disable automatic deployment about OTC profile (#456) * change tx history query to have better performance * update trx security filter * fix reference of currencies comparation ( object -> symbol) * seprate withdraw categories based on steps, enable unlimited report history * add withdraw filed to tx history resp * fix withdraw settelment filed to tx history resp * expose chains information service * change permission of getChainsInfo * fix query syntax * start developing new service to fetch tx history * fetch tx of trades table to have new tx history service * Save deposit tx seprately * develop new service to fetch deposit history * handle self-trade in fetching transactions * fix query bug * fix query bug * change in logic of manual deposit * change method type in fetching withdraw history * change method type in fetching trades' tx history * Change date format in some services * Disable automatic deployment about otc profile --- .github/workflows/dev-otc.yml | 6 +++--- .github/workflows/main-otc.yml | 6 +++--- .../opex/api/ports/binance/controller/WalletController.kt | 4 ++-- .../nilin/opex/wallet/app/controller/WithdrawController.kt | 2 ++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/dev-otc.yml b/.github/workflows/dev-otc.yml index e5e6a2c23..5d3350abb 100644 --- a/.github/workflows/dev-otc.yml +++ b/.github/workflows/dev-otc.yml @@ -1,8 +1,8 @@ name: Build, Test, and Deploy otc (DEV env) services for specific partner on: - push: - branches: - - dev +# push: +# branches: +# - dev workflow_dispatch: inputs: diff --git a/.github/workflows/main-otc.yml b/.github/workflows/main-otc.yml index 7c366120f..78d28f174 100644 --- a/.github/workflows/main-otc.yml +++ b/.github/workflows/main-otc.yml @@ -1,8 +1,8 @@ name: Build, Test, and Deploy otc (PRD env) services for specific partner on: - push: - branches: - - main +# push: +# branches: +# - main workflow_dispatch: inputs: diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt index 878918254..2185ec49b 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt @@ -76,7 +76,7 @@ class WalletController( securityContext.jwtAuthentication().tokenValue(), coin, startTime ?: null, - endTime ?: Date().time, + endTime ?: null, if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, offset ?: 0, ascendingByTime @@ -154,7 +154,7 @@ class WalletController( @PostMapping("/v2/capital/withdraw/history") suspend fun getWithdrawTransactionsV2( - @RequestBody withdrawRequest:WithDrawRequest, + @RequestBody withdrawRequest: WithDrawRequest, @CurrentSecurityContext securityContext: SecurityContext ): List { val validLimit = withdrawRequest.limit ?: 1000 diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt index 3e9062882..4c5b57348 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/WithdrawController.kt @@ -118,6 +118,8 @@ class WithdrawController(private val withdrawService: WithdrawService) { request.offset!!, request.ascendingByTime ).map { + + WithdrawHistoryResponse( it.withdrawId, it.ownerUuid, From 2d048d23394867a9d2247d289f25baab1939ef63 Mon Sep 17 00:00:00 2001 From: Peyman Date: Sat, 6 Jul 2024 18:46:22 +0330 Subject: [PATCH 7/9] Add logbook for better logs (#458) * Add logbook * Add logging level in wallet * Remove loggin-handler * Clean up order book log --- accountant/accountant-app/pom.xml | 4 - .../src/main/resources/application.yml | 34 +- .../accountant-wallet-proxy/pom.xml | 4 - .../walletproxy/config/WebClientConfig.kt | 25 +- accountant/pom.xml | 10 +- api/api-app/pom.xml | 4 - .../src/main/resources/application.yml | 37 +- api/api-ports/api-binance-rest/pom.xml | 4 - .../ports/binance/config/WebClientConfig.kt | 17 +- .../binance/controller/WalletController.kt | 332 +++++++++--------- api/api-ports/api-opex-rest/pom.xml | 4 - .../api/ports/opex/config/WebClientConfig.kt | 15 +- api/pom.xml | 10 +- bc-gateway/bc-gateway-app/pom.xml | 5 + .../bcgateway/app/config/WebClientConfig.kt | 16 +- .../src/main/resources/application.yml | 33 +- bc-gateway/pom.xml | 5 - eventlog/pom.xml | 5 - market/market-app/pom.xml | 4 - .../opex/market/app/config/WebClientConfig.kt | 14 +- .../src/main/resources/application.yml | 35 +- .../ports/postgres/util/RedisCacheHelper.kt | 6 +- market/pom.xml | 10 +- .../src/main/resources/application.yml | 3 +- .../engine/core/engine/SimpleOrderBook.kt | 44 ++- matching-engine/pom.xml | 5 - matching-gateway/matching-gateway-app/pom.xml | 4 - .../gateway/app/config/WebClientConfig.kt | 24 +- .../src/main/resources/application.yml | 37 +- matching-gateway/pom.xml | 10 +- pom.xml | 1 - wallet/pom.xml | 10 +- wallet/wallet-app/pom.xml | 5 - .../opex/wallet/app/config/WebClientConfig.kt | 24 +- .../src/main/resources/application.yml | 41 ++- 35 files changed, 468 insertions(+), 373 deletions(-) diff --git a/accountant/accountant-app/pom.xml b/accountant/accountant-app/pom.xml index 8c15f9213..f722891eb 100644 --- a/accountant/accountant-app/pom.xml +++ b/accountant/accountant-app/pom.xml @@ -51,10 +51,6 @@ co.nilin.opex.utility error-handler - - co.nilin.opex.utility - logging-handler - org.springframework.cloud spring-cloud-starter-vault-config diff --git a/accountant/accountant-app/src/main/resources/application.yml b/accountant/accountant-app/src/main/resources/application.yml index 1c7b609ba..1d4c48dd3 100644 --- a/accountant/accountant-app/src/main/resources/application.yml +++ b/accountant/accountant-app/src/main/resources/application.yml @@ -1,8 +1,5 @@ -server.port: 8080 -logging: - level: - co.nilin: INFO - reactor.netty.http.client: INFO +server: + port: 8080 spring: application: name: opex-accountant @@ -67,6 +64,33 @@ management: enabled: true prometheus: enabled: true +logbook: + secure-filter: + enabled: true + format: + style: http + filter: + enabled: true + form-request-mode: BODY + obfuscate: + headers: + - Authorization + parameters: + - password + json-body-fields: + - password + replacement: "***" + write: + max-body-size: 5_000 #kb + predicate: + exclude: + - path: /auth** + - path: /actuator/** + - path: /swagger** +logging: + level: + co.nilin: INFO + org.zalando.logbook: TRACE app: address: 1 wallet: diff --git a/accountant/accountant-ports/accountant-wallet-proxy/pom.xml b/accountant/accountant-ports/accountant-wallet-proxy/pom.xml index d489e8bec..3819743c8 100644 --- a/accountant/accountant-ports/accountant-wallet-proxy/pom.xml +++ b/accountant/accountant-ports/accountant-wallet-proxy/pom.xml @@ -28,10 +28,6 @@ co.nilin.opex.accountant.core accountant-core - - co.nilin.opex.utility - logging-handler - org.springframework.boot spring-boot-starter-webflux diff --git a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt index 718eade2b..dc33ddf7e 100644 --- a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt +++ b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt @@ -1,37 +1,24 @@ package co.nilin.opex.accountant.ports.walletproxy.config -import co.nilin.opex.utility.log.CustomLogger import org.springframework.cloud.client.ServiceInstance -import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean - fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory): WebClient { - val logger = CustomLogger(HttpClient::class.java) - return WebClient.builder() - .clientConnector( - ReactorClientHttpConnector( - HttpClient - .create() - .doOnRequest { request, connection -> - connection.addHandlerFirst(logger) - } - ) - ) - .filter( - ReactorLoadBalancerExchangeFilterFunction( - loadBalancerFactory, LoadBalancerProperties(), emptyList() - ) - ) + fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } + return WebClient.builder().clientConnector(ReactorClientHttpConnector(client)) + .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/accountant/pom.xml b/accountant/pom.xml index ee83bb892..15916c8d3 100644 --- a/accountant/pom.xml +++ b/accountant/pom.xml @@ -33,6 +33,11 @@ co.nilin.opex common + + org.zalando + logbook-spring-boot-webflux-autoconfigure + 3.9.0 + io.mockk mockk @@ -77,11 +82,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility preferences diff --git a/api/api-app/pom.xml b/api/api-app/pom.xml index c1f78a0b9..d27d6e876 100644 --- a/api/api-app/pom.xml +++ b/api/api-app/pom.xml @@ -31,10 +31,6 @@ org.springframework.boot spring-boot-starter-cache - - co.nilin.opex.utility - logging-handler - co.nilin.opex.utility error-handler diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 2ef7ff477..cda25dff9 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -1,8 +1,5 @@ -server.port: 8080 -logging: - level: - co.nilin: INFO - reactor.netty.http.client: DEBUG +server: + port: 8080 spring: application: name: opex-api @@ -57,6 +54,33 @@ management: enabled: true prometheus: enabled: true +logbook: + secure-filter: + enabled: true + format: + style: http + filter: + enabled: true + form-request-mode: BODY + obfuscate: + headers: + - Authorization + parameters: + - password + json-body-fields: + - password + replacement: "***" + write: + max-body-size: 10_000 #kb + predicate: + exclude: + - path: /auth** + - path: /actuator/** + - path: /swagger** +logging: + level: + co.nilin: INFO + org.zalando.logbook: TRACE app: accountant: url: lb://opex-accountant @@ -75,4 +99,5 @@ app: secret: ${API_KEY_CLIENT_SECRET} binance: api-url: https://api1.binance.com -swagger.authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token +swagger: + authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token diff --git a/api/api-ports/api-binance-rest/pom.xml b/api/api-ports/api-binance-rest/pom.xml index 6d066d328..2808edc0a 100644 --- a/api/api-ports/api-binance-rest/pom.xml +++ b/api/api-ports/api-binance-rest/pom.xml @@ -24,10 +24,6 @@ co.nilin.opex.api.core api-core - - co.nilin.opex.utility - logging-handler - co.nilin.opex.utility error-handler diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt index 2248bd0b4..055d19033 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt @@ -1,31 +1,24 @@ package co.nilin.opex.api.ports.binance.config -import co.nilin.opex.utility.log.CustomLogger -import org.springframework.beans.factory.annotation.Qualifier import org.springframework.cloud.client.ServiceInstance import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Primary import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean - fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory): WebClient { - val logger = CustomLogger(HttpClient::class.java) + fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector( - ReactorClientHttpConnector( - HttpClient - .create() - .doOnRequest { _, connection -> connection.addHandlerFirst(logger) } - ) - ) + .clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt index 2185ec49b..e9ef41d5a 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt @@ -23,24 +23,24 @@ import java.util.* @RestController class WalletController( - private val walletProxy: WalletProxy, - private val symbolMapper: SymbolMapper, - private val marketDataProxy: MarketDataProxy, - private val accountantProxy: AccountantProxy, - private val bcGatewayProxy: BlockchainGatewayProxy, + private val walletProxy: WalletProxy, + private val symbolMapper: SymbolMapper, + private val marketDataProxy: MarketDataProxy, + private val accountantProxy: AccountantProxy, + private val bcGatewayProxy: BlockchainGatewayProxy, ) { @GetMapping("/v1/capital/deposit/address") suspend fun assignAddress( - @RequestParam - coin: String, - @RequestParam - network: String, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long, - @CurrentSecurityContext securityContext: SecurityContext + @RequestParam + coin: String, + @RequestParam + network: String, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long, + @CurrentSecurityContext securityContext: SecurityContext ): AssignAddressResponse { val response = bcGatewayProxy.assignAddress(securityContext.jwtAuthentication().name, coin, network) val address = response?.addresses @@ -50,36 +50,36 @@ class WalletController( @GetMapping("/v1/capital/deposit/hisrec") suspend fun getDepositTransactions( - @RequestParam(required = false) - coin: String?, - @RequestParam("network", required = false) - status: Int?, - @RequestParam(required = false) - startTime: Long?, - @RequestParam(required = false) - endTime: Long?, - @RequestParam(required = false) - offset: Int?, - @RequestParam(required = false) - limit: Int?, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long, - @RequestParam(required = false) - ascendingByTime: Boolean? = false, - @CurrentSecurityContext securityContext: SecurityContext + @RequestParam(required = false) + coin: String?, + @RequestParam("network", required = false) + status: Int?, + @RequestParam(required = false) + startTime: Long?, + @RequestParam(required = false) + endTime: Long?, + @RequestParam(required = false) + offset: Int?, + @RequestParam(required = false) + limit: Int?, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long, + @RequestParam(required = false) + ascendingByTime: Boolean? = false, + @CurrentSecurityContext securityContext: SecurityContext ): List { val validLimit = limit ?: 1000 val deposits = walletProxy.getDepositTransactions( - securityContext.jwtAuthentication().name, - securityContext.jwtAuthentication().tokenValue(), - coin, - startTime ?: null, - endTime ?: null, - if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, - offset ?: 0, - ascendingByTime + securityContext.jwtAuthentication().name, + securityContext.jwtAuthentication().tokenValue(), + coin, + startTime ?: null, + endTime ?: null, + if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, + offset ?: 0, + ascendingByTime ) if (deposits.isEmpty()) return emptyList() @@ -90,38 +90,38 @@ class WalletController( @GetMapping("/v1/capital/withdraw/history") suspend fun getWithdrawTransactions( - @RequestParam(required = false) - coin: String, - @RequestParam(required = false) - withdrawOrderId: String?, - @RequestParam("status", required = false) - withdrawStatus: Int?, - @RequestParam(required = false) - offset: Int?, - @RequestParam(required = false) - limit: Int?, - @RequestParam(required = false) - startTime: Long?, - @RequestParam(required = false) - endTime: Long?, - @RequestParam(required = false) - ascendingByTime: Boolean? = false, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long, - @CurrentSecurityContext securityContext: SecurityContext + @RequestParam(required = false) + coin: String, + @RequestParam(required = false) + withdrawOrderId: String?, + @RequestParam("status", required = false) + withdrawStatus: Int?, + @RequestParam(required = false) + offset: Int?, + @RequestParam(required = false) + limit: Int?, + @RequestParam(required = false) + startTime: Long?, + @RequestParam(required = false) + endTime: Long?, + @RequestParam(required = false) + ascendingByTime: Boolean? = false, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long, + @CurrentSecurityContext securityContext: SecurityContext ): List { val validLimit = limit ?: 1000 val response = walletProxy.getWithdrawTransactions( - securityContext.jwtAuthentication().name, - securityContext.jwtAuthentication().tokenValue(), - coin, - startTime ?: null, - endTime ?: null, - if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, - offset ?: 0, - ascendingByTime + securityContext.jwtAuthentication().name, + securityContext.jwtAuthentication().tokenValue(), + coin, + startTime ?: null, + endTime ?: null, + if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, + offset ?: 0, + ascendingByTime ) return response.map { val status = when (it.status) { @@ -132,21 +132,21 @@ class WalletController( } WithdrawResponse( - it.destAddress ?: "0x0", - it.amount, - LocalDateTime.ofInstant(Instant.ofEpochMilli(it.createDate), ZoneId.systemDefault()) - .toString() - .replace("T", " "), - it.destSymbol ?: "", - it.withdrawId?.toString() ?: "", - "", - it.destNetwork ?: "", - 1, - status, - it.appliedFee.toString(), - 3, - it.destTransactionRef ?: it.withdrawId.toString(), - if (status == 1 && it.acceptDate != null) it.acceptDate!! else it.createDate + it.destAddress ?: "0x0", + it.amount, + LocalDateTime.ofInstant(Instant.ofEpochMilli(it.createDate), ZoneId.systemDefault()) + .toString() + .replace("T", " "), + it.destSymbol ?: "", + it.withdrawId?.toString() ?: "", + "", + it.destNetwork ?: "", + 1, + status, + it.appliedFee.toString(), + 3, + it.destTransactionRef ?: it.withdrawId.toString(), + if (status == 1 && it.acceptDate != null) it.acceptDate!! else it.createDate ) } } @@ -154,19 +154,19 @@ class WalletController( @PostMapping("/v2/capital/withdraw/history") suspend fun getWithdrawTransactionsV2( - @RequestBody withdrawRequest: WithDrawRequest, - @CurrentSecurityContext securityContext: SecurityContext + @RequestBody withdrawRequest: WithDrawRequest, + @CurrentSecurityContext securityContext: SecurityContext ): List { val validLimit = withdrawRequest.limit ?: 1000 val response = walletProxy.getWithdrawTransactions( - securityContext.jwtAuthentication().name, - securityContext.jwtAuthentication().tokenValue(), - withdrawRequest.coin, - withdrawRequest.startTime ?: null, - withdrawRequest.endTime ?: null, - if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, - withdrawRequest.offset ?: 0, - withdrawRequest.ascendingByTime + securityContext.jwtAuthentication().name, + securityContext.jwtAuthentication().tokenValue(), + withdrawRequest.coin, + withdrawRequest.startTime ?: null, + withdrawRequest.endTime ?: null, + if (validLimit > 1000 || validLimit < 1) 1000 else validLimit, + withdrawRequest.offset ?: 0, + withdrawRequest.ascendingByTime ) return response.map { val status = when (it.status) { @@ -177,33 +177,33 @@ class WalletController( } WithdrawResponse( - it.destAddress ?: "0x0", - it.amount, - LocalDateTime.ofInstant(Instant.ofEpochMilli(it.createDate), ZoneId.systemDefault()) - .toString() - .replace("T", " "), - it.destSymbol ?: "", - it.withdrawId?.toString() ?: "", - "", - it.destNetwork ?: "", - 1, - status, - it.appliedFee.toString(), - 3, - it.destTransactionRef ?: it.withdrawId.toString(), - if (status == 1 && it.acceptDate != null) it.acceptDate!! else it.createDate + it.destAddress ?: "0x0", + it.amount, + LocalDateTime.ofInstant(Instant.ofEpochMilli(it.createDate), ZoneId.systemDefault()) + .toString() + .replace("T", " "), + it.destSymbol ?: "", + it.withdrawId?.toString() ?: "", + "", + it.destNetwork ?: "", + 1, + status, + it.appliedFee.toString(), + 3, + it.destTransactionRef ?: it.withdrawId.toString(), + if (status == 1 && it.acceptDate != null) it.acceptDate!! else it.createDate ) } } @GetMapping("/v1/asset/tradeFee") suspend fun getPairFees( - @RequestParam(required = false) - symbol: String?, - @RequestParam(required = false) - recvWindow: Long?, //The value cannot be greater than 60000 - @RequestParam - timestamp: Long + @RequestParam(required = false) + symbol: String?, + @RequestParam(required = false) + recvWindow: Long?, //The value cannot be greater than 60000 + @RequestParam + timestamp: Long ): List { return if (symbol != null) { val internalSymbol = symbolMapper.toInternalSymbol(symbol) ?: throw OpexError.SymbolNotFound.exception() @@ -211,35 +211,35 @@ class WalletController( val fee = accountantProxy.getFeeConfig(internalSymbol) arrayListOf().apply { add( - PairFeeResponse( - symbol, - fee.makerFee.toDouble(), - fee.takerFee.toDouble() - ) + PairFeeResponse( + symbol, + fee.makerFee.toDouble(), + fee.takerFee.toDouble() + ) ) } } else accountantProxy.getFeeConfigs() - .distinctBy { it.pair } - .map { - PairFeeResponse( - symbolMapper.fromInternalSymbol(it.pair) ?: it.pair, - it.makerFee.toDouble(), - it.takerFee.toDouble() - ) - } + .distinctBy { it.pair } + .map { + PairFeeResponse( + symbolMapper.fromInternalSymbol(it.pair) ?: it.pair, + it.makerFee.toDouble(), + it.takerFee.toDouble() + ) + } } @GetMapping("/v1/asset/getUserAsset") suspend fun getUserAssets( - @CurrentSecurityContext - securityContext: SecurityContext, - @RequestParam(required = false) - symbol: String?, - @RequestParam(required = false) - quoteAsset: String?, - @RequestParam(required = false) - calculateEvaluation: Boolean? + @CurrentSecurityContext + securityContext: SecurityContext, + @RequestParam(required = false) + symbol: String?, + @RequestParam(required = false) + quoteAsset: String?, + @RequestParam(required = false) + calculateEvaluation: Boolean? ): List { val auth = securityContext.jwtAuthentication() val result = arrayListOf() @@ -249,8 +249,8 @@ class WalletController( result.add(AssetResponse(wallet.asset, wallet.balance, wallet.locked, wallet.withdraw)) } else { result.addAll( - walletProxy.getWallets(auth.name, auth.tokenValue()) - .map { AssetResponse(it.asset, it.balance, it.locked, it.withdraw) } + walletProxy.getWallets(auth.name, auth.tokenValue()) + .map { AssetResponse(it.asset, it.balance, it.locked, it.withdraw) } ) } @@ -258,11 +258,11 @@ class WalletController( return result val prices = marketDataProxy.getBestPriceForSymbols( - result.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } + result.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } ).associateBy { it.symbol.split("_")[0] } result.associateWith { prices[it.asset] } - .forEach { (asset, price) -> asset.valuation = price?.bidPrice ?: BigDecimal.ZERO } + .forEach { (asset, price) -> asset.valuation = price?.bidPrice ?: BigDecimal.ZERO } if (calculateEvaluation == true) result.forEach { @@ -276,32 +276,32 @@ class WalletController( @GetMapping("/v1/asset/estimatedValue") suspend fun assetsEstimatedValue( - @CurrentSecurityContext - securityContext: SecurityContext, - @RequestParam - quoteAsset: String + @CurrentSecurityContext + securityContext: SecurityContext, + @RequestParam + quoteAsset: String ): AssetsEstimatedValue { val auth = securityContext.jwtAuthentication() val wallets = walletProxy.getWallets(auth.name, auth.tokenValue()) val rates = marketDataProxy.getBestPriceForSymbols( - wallets.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } + wallets.map { "${it.asset.uppercase()}_${quoteAsset.uppercase()}" } ).associateBy { it.symbol.split("_")[0] } var value = BigDecimal.ZERO val zeroAssets = arrayListOf() wallets.associateWith { rates[it.asset] } - .forEach { (asset, price) -> - if (price == null || (price.bidPrice ?: BigDecimal.ZERO) == BigDecimal.ZERO) - zeroAssets.add(asset.asset) - else - value += asset.balance.multiply(price.bidPrice) - } + .forEach { (asset, price) -> + if (price == null || (price.bidPrice ?: BigDecimal.ZERO) == BigDecimal.ZERO) + zeroAssets.add(asset.asset) + else + value += asset.balance.multiply(price.bidPrice) + } return AssetsEstimatedValue(value, quoteAsset.uppercase(), zeroAssets) } private fun matchDepositsAndDetails( - deposits: List, - details: List + deposits: List, + details: List ): List { val detailMap = details.associateBy { it.hash } return deposits.associateWith { @@ -309,18 +309,18 @@ class WalletController( }.mapNotNull { (deposit, detail) -> detail?.let { DepositResponse( - deposit.amount, - deposit.currency, - detail.chain, - 1, - detail.address, - null, - deposit.ref ?: deposit.id.toString(), - deposit.date, - 1, - "1/1", - "1/1", - deposit.date + deposit.amount, + deposit.currency, + detail.chain, + 1, + detail.address, + null, + deposit.ref ?: deposit.id.toString(), + deposit.date, + 1, + "1/1", + "1/1", + deposit.date ) } } diff --git a/api/api-ports/api-opex-rest/pom.xml b/api/api-ports/api-opex-rest/pom.xml index f34202673..50a08fdce 100644 --- a/api/api-ports/api-opex-rest/pom.xml +++ b/api/api-ports/api-opex-rest/pom.xml @@ -24,10 +24,6 @@ co.nilin.opex.api.core api-core - - co.nilin.opex.utility - logging-handler - co.nilin.opex.utility error-handler diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt index 66efb849f..c5e5aa387 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt @@ -1,6 +1,5 @@ package co.nilin.opex.api.ports.opex.config -import co.nilin.opex.utility.log.CustomLogger import org.springframework.cloud.client.ServiceInstance import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction @@ -8,22 +7,18 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean - fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory): WebClient { - val logger = CustomLogger(HttpClient::class.java) + fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector( - ReactorClientHttpConnector( - HttpClient - .create() - .doOnRequest { _, connection -> connection.addHandlerFirst(logger) } - ) - ) + .clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/api/pom.xml b/api/pom.xml index 148ebc231..2c8ff9694 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -33,6 +33,11 @@ co.nilin.opex common + + org.zalando + logbook-spring-boot-webflux-autoconfigure + 3.9.0 + @@ -62,11 +67,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility interceptors diff --git a/bc-gateway/bc-gateway-app/pom.xml b/bc-gateway/bc-gateway-app/pom.xml index fe5717bb5..86f6888d3 100644 --- a/bc-gateway/bc-gateway-app/pom.xml +++ b/bc-gateway/bc-gateway-app/pom.xml @@ -95,6 +95,11 @@ bcprov-jdk15on 1.60 + + org.zalando + logbook-spring-boot-webflux-autoconfigure + 3.9.0 + co.nilin.opex.bcgateway.core bc-gateway-core diff --git a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt index 11fbc3278..de3e8b5cf 100644 --- a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt +++ b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt @@ -1,23 +1,27 @@ package co.nilin.opex.bcgateway.app.config -import org.springframework.beans.factory.annotation.Qualifier import org.springframework.cloud.client.ServiceInstance -import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Profile +import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.ExchangeStrategies import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler +import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean -@Profile("!otc") - fun loadBalancedWebClient(loadBalancerFactory: ReactiveLoadBalancer.Factory): WebClient { + @Profile("!otc") + fun loadBalancedWebClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() + .clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .exchangeStrategies( ExchangeStrategies.builder() @@ -29,8 +33,10 @@ class WebClientConfig { @Bean @Profile("otc") - fun webClient(): WebClient { + fun webClient(logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() + .clientConnector(ReactorClientHttpConnector(client)) .exchangeStrategies( ExchangeStrategies.builder() .codecs { it.defaultCodecs().maxInMemorySize(20 * 1024 * 1024) } diff --git a/bc-gateway/bc-gateway-app/src/main/resources/application.yml b/bc-gateway/bc-gateway-app/src/main/resources/application.yml index 593b1a7d1..7248b254a 100644 --- a/bc-gateway/bc-gateway-app/src/main/resources/application.yml +++ b/bc-gateway/bc-gateway-app/src/main/resources/application.yml @@ -1,4 +1,5 @@ -server.port: 8080 +server: + port: 8080 spring: application: name: opex-bc-gateway @@ -55,12 +56,34 @@ management: enabled: true prometheus: enabled: true +logbook: + secure-filter: + enabled: true + format: + style: http + filter: + enabled: true + form-request-mode: BODY + obfuscate: + headers: + - Authorization + parameters: + - password + json-body-fields: + - password + replacement: "***" + write: + max-body-size: 1_000 #kb + predicate: + exclude: + - path: /auth** + - path: /actuator/** + - path: /swagger** logging: level: org.apache.kafka: ERROR co.nilin: INFO -swagger: - authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token + org.zalando.logbook: TRACE app: auth: url: lb://opex-auth @@ -71,5 +94,7 @@ app: url: lb://opex-wallet address: life-time: - value: ${ADDRESS_EXP_TIME} # second + value: ${ADDRESS_EXP_TIME} # second +swagger: + authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token} diff --git a/bc-gateway/pom.xml b/bc-gateway/pom.xml index 6c163bc8f..cc2ddb897 100644 --- a/bc-gateway/pom.xml +++ b/bc-gateway/pom.xml @@ -66,11 +66,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility interceptors diff --git a/eventlog/pom.xml b/eventlog/pom.xml index 487b3068e..bc56375fa 100644 --- a/eventlog/pom.xml +++ b/eventlog/pom.xml @@ -60,11 +60,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility interceptors diff --git a/market/market-app/pom.xml b/market/market-app/pom.xml index d563336f4..37d7e0e47 100644 --- a/market/market-app/pom.xml +++ b/market/market-app/pom.xml @@ -51,10 +51,6 @@ org.springframework.boot spring-boot-starter - - co.nilin.opex.utility - logging-handler - co.nilin.opex.utility error-handler diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt index b9a804522..8c59fc3fe 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt @@ -6,19 +6,21 @@ import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalanc import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler +import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean - fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory): WebClient { + fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .filter( - ReactorLoadBalancerExchangeFilterFunction( - loadBalancerFactory, LoadBalancerProperties(), emptyList() - ) - ) + .clientConnector(ReactorClientHttpConnector(client)) + .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/market/market-app/src/main/resources/application.yml b/market/market-app/src/main/resources/application.yml index 5bc7f23d2..2e1f1510e 100644 --- a/market/market-app/src/main/resources/application.yml +++ b/market/market-app/src/main/resources/application.yml @@ -1,8 +1,5 @@ -server.port: 8080 -logging: - level: - co.nilin: INFO - reactor.netty.http.client: DEBUG +server: + port: 8080 spring: application: name: opex-market @@ -61,8 +58,34 @@ management: enabled: true prometheus: enabled: true +logbook: + secure-filter: + enabled: true + format: + style: http + filter: + enabled: true + form-request-mode: BODY + obfuscate: + headers: + - Authorization + parameters: + - password + json-body-fields: + - password + replacement: "***" + write: + max-body-size: 10_000 #kb + predicate: + exclude: + - path: /auth** + - path: /actuator/** + - path: /swagger** +logging: + level: + co.nilin: INFO app: auth: cert-url: lb://opex-auth/auth/realms/opex/protocol/openid-connect/certs swagger: - authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token + authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token} diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/RedisCacheHelper.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/RedisCacheHelper.kt index ed0e5ae57..31bac2103 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/RedisCacheHelper.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/util/RedisCacheHelper.kt @@ -71,8 +71,10 @@ class RedisCacheHelper(private val redisTemplate: RedisTemplate) { cacheValue else { val value = action() - put(key, value!!) - expireAt?.let { setExpiration(key, it) } + if (value != null) { + put(key, value) + expireAt?.let { setExpiration(key, it) } + } return value } } diff --git a/market/pom.xml b/market/pom.xml index 07d3d0a3b..e64de9679 100644 --- a/market/pom.xml +++ b/market/pom.xml @@ -31,6 +31,11 @@ co.nilin.opex common + + org.zalando + logbook-spring-boot-webflux-autoconfigure + 3.9.0 + @@ -60,11 +65,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility interceptors diff --git a/matching-engine/matching-engine-app/src/main/resources/application.yml b/matching-engine/matching-engine-app/src/main/resources/application.yml index 9eca83755..bf56a1135 100644 --- a/matching-engine/matching-engine-app/src/main/resources/application.yml +++ b/matching-engine/matching-engine-app/src/main/resources/application.yml @@ -1,4 +1,5 @@ -server.port: 8080 +server: + port: 8080 spring: main: allow-bean-definition-overriding: false diff --git a/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt b/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt index 7b01bac7b..7803d365c 100644 --- a/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt +++ b/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt @@ -86,6 +86,7 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { } queueOrder } + MatchConstraint.IOC -> { val order = SimpleOrder( orderCounter.incrementAndGet(), @@ -133,6 +134,7 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { } queueOrder } + else -> { if (!replayMode) { EventDispatcher.emit( @@ -271,6 +273,7 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { EventDispatcher.emit(OrderBookPublishedEvent(persistent())) queueOrder } + MatchConstraint.IOC -> { if (!replayMode) { EventDispatcher.emit( @@ -313,6 +316,7 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { EventDispatcher.emit(OrderBookPublishedEvent(persistent())) queueOrder } + else -> { if (!replayMode) { EventDispatcher.emit( @@ -577,24 +581,32 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { } private fun logNewOrder(orderCommand: OrderCreateCommand) { - logger.info("****************** new order received *******************") - logger.info("** order id: ${orderCommand.ouid}") - logger.info("** price: ${orderCommand.price}") - logger.info("** quantity: ${orderCommand.quantity}") - logger.info("** direction: ${orderCommand.direction}") - logger.info("*********************************************************") - println() + logger.info( + """ + ++++ NEW ${orderCommand.pair.leftSideName}-${orderCommand.pair.rightSideName} + - ouid: ${orderCommand.ouid}") + - price: ${orderCommand.price}") + - quantity: ${orderCommand.quantity}") + - direction: ${orderCommand.direction}") + ******************************************** + + """.trimIndent() + ) } private fun logCurrentState() { - logger.info("******************** ${pair.leftSideName}-${pair.rightSideName} ********************") - logger.info("** askOrders size: ${askOrders.entriesList().size}") - logger.info("** bidOrders size: ${bidOrders.entriesList().size}") - logger.info("** orders size: ${orders.size}") - logger.info("** bestAskOrder: ${bestAskOrder?.ouid}") - logger.info("** bestBidOrder: ${bestBidOrder?.ouid}") - logger.info("** lastOrder: ${lastOrder?.ouid}") - logger.info("*********************************************************") - println() + logger.info( + """ + ==== STATE ${pair.leftSideName}-${pair.rightSideName} + - askOrders size: ${askOrders.entriesList().size} + - bidOrders size: ${bidOrders.entriesList().size} + - orders size: ${orders.size} + - bestAskOrder: ${bestAskOrder?.ouid} + - bestBidOrder: ${bestBidOrder?.ouid} + - lastOrder: ${lastOrder?.ouid} + ******************************************** + + """.trimIndent() + ) } } \ No newline at end of file diff --git a/matching-engine/pom.xml b/matching-engine/pom.xml index 21fde44ba..737dabe1d 100644 --- a/matching-engine/pom.xml +++ b/matching-engine/pom.xml @@ -57,11 +57,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility interceptors diff --git a/matching-gateway/matching-gateway-app/pom.xml b/matching-gateway/matching-gateway-app/pom.xml index 647109705..821456c1b 100644 --- a/matching-gateway/matching-gateway-app/pom.xml +++ b/matching-gateway/matching-gateway-app/pom.xml @@ -69,10 +69,6 @@ co.nilin.opex.utility error-handler - - co.nilin.opex.utility - logging-handler - io.mockk mockk diff --git a/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt b/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt index d87916b6e..dc4ccef9d 100644 --- a/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt +++ b/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt @@ -1,37 +1,25 @@ package co.nilin.opex.matching.gateway.app.config -import co.nilin.opex.utility.log.CustomLogger import org.springframework.cloud.client.ServiceInstance -import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean - fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory): WebClient { - val logger = CustomLogger(HttpClient::class.java) + fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector( - ReactorClientHttpConnector( - HttpClient - .create() - .doOnRequest { request, connection -> - connection.addHandlerFirst(logger) - } - ) - ) - .filter( - ReactorLoadBalancerExchangeFilterFunction( - loadBalancerFactory, LoadBalancerProperties(), emptyList() - ) - ) + .clientConnector(ReactorClientHttpConnector(client)) + .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/matching-gateway/matching-gateway-app/src/main/resources/application.yml b/matching-gateway/matching-gateway-app/src/main/resources/application.yml index df6cbd82c..d41c02452 100644 --- a/matching-gateway/matching-gateway-app/src/main/resources/application.yml +++ b/matching-gateway/matching-gateway-app/src/main/resources/application.yml @@ -1,8 +1,5 @@ -server.port: 8080 -logging: - level: - co.nilin: INFO - reactor.netty.http.client: DEBUG +server: + port: 8080 spring: application: name: opex-matching-gateway @@ -36,9 +33,37 @@ management: enabled: true prometheus: enabled: true -swagger.authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token +logbook: + secure-filter: + enabled: true + format: + style: http + filter: + enabled: true + form-request-mode: BODY + obfuscate: + headers: + - Authorization + parameters: + - password + json-body-fields: + - password + replacement: "***" + write: + max-body-size: 10_000 #kb + predicate: + exclude: + - path: /auth** + - path: /actuator/** + - path: /swagger** +logging: + level: + co.nilin: INFO + org.zalando.logbook: TRACE app: accountant: url: lb://opex-accountant auth: cert-url: lb://opex-auth/auth/realms/opex/protocol/openid-connect/certs +swagger: + authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token} diff --git a/matching-gateway/pom.xml b/matching-gateway/pom.xml index aaa52ca7d..3fd2fe323 100644 --- a/matching-gateway/pom.xml +++ b/matching-gateway/pom.xml @@ -29,6 +29,11 @@ co.nilin.opex common + + org.zalando + logbook-spring-boot-webflux-autoconfigure + 3.9.0 + @@ -48,11 +53,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility interceptors diff --git a/pom.xml b/pom.xml index 88c50a8d7..f9d9cd172 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,6 @@ 2.7.6 2021.0.5 1.0.0 - 1.0.0 1.0.0 1.0.0 true diff --git a/wallet/pom.xml b/wallet/pom.xml index c5ddd9aea..e5fef7d07 100644 --- a/wallet/pom.xml +++ b/wallet/pom.xml @@ -33,6 +33,11 @@ co.nilin.opex common + + org.zalando + logbook-spring-boot-webflux-autoconfigure + 3.9.0 + @@ -67,11 +72,6 @@ error-handler ${error-hanlder.version} - - co.nilin.opex.utility - logging-handler - ${logging-handler.version} - co.nilin.opex.utility interceptors diff --git a/wallet/wallet-app/pom.xml b/wallet/wallet-app/pom.xml index 4627575eb..2b2a34e3b 100644 --- a/wallet/wallet-app/pom.xml +++ b/wallet/wallet-app/pom.xml @@ -107,11 +107,6 @@ co.nilin.opex.utility error-handler - - co.nilin.opex.utility - logging-handler - - org.springframework.boot spring-boot-starter-actuator diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt index 2310eeabe..8302c6ae0 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt @@ -2,13 +2,16 @@ package co.nilin.opex.wallet.app.config import org.springframework.beans.factory.annotation.Qualifier import org.springframework.cloud.client.ServiceInstance -import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerExchangeFilterFunction import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Profile +import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler +import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @@ -16,22 +19,25 @@ class WebClientConfig { @Bean @Profile("!otc") @Qualifier("loadBalanced") - fun loadBalancedWebClient(loadBalancerFactory: ReactiveLoadBalancer.Factory): WebClient { + fun loadBalancedWebClient( + loadBalancerFactory: ReactiveLoadBalancer.Factory, + logbook: Logbook + ): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .filter( - ReactorLoadBalancerExchangeFilterFunction( - loadBalancerFactory, LoadBalancerProperties(), emptyList() - ) - ) + .clientConnector(ReactorClientHttpConnector(client)) + .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } @Bean @Profile("otc") @Qualifier("decWebClient") - fun webClient(): WebClient { + fun webClient(logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .build() + .clientConnector(ReactorClientHttpConnector(client)) + .build() } } diff --git a/wallet/wallet-app/src/main/resources/application.yml b/wallet/wallet-app/src/main/resources/application.yml index ed9961846..da17a6608 100644 --- a/wallet/wallet-app/src/main/resources/application.yml +++ b/wallet/wallet-app/src/main/resources/application.yml @@ -1,4 +1,5 @@ -server.port: 8080 +server: + port: 8080 management: endpoints: web: @@ -56,6 +57,35 @@ spring: prefer-ip-address: true config: import: vault://secret/${spring.application.name} +logbook: + secure-filter: + enabled: true + format: + style: http + filter: + enabled: true + form-request-mode: BODY + obfuscate: + headers: + - Authorization + parameters: + - password + json-body-fields: + - password + replacement: "***" + write: + max-body-size: 10_000 #kb + predicate: + exclude: + - path: /auth** + - path: /actuator/** + - path: /swagger** +logging: + level: + root: INFO + org.apache.kafka: ERROR + co.nilin: INFO + org.zalando.logbook: TRACE app: auth: url: lb://opex-auth @@ -72,10 +102,5 @@ app: url: lb://opex-bc-gateway reserved-transfer: life-time: 15 #minutes -logging: - level: - root: INFO - org.apache.kafka: ERROR - co.nilin: INFO - reactor.netty.http.client: INFO -swagger.authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token +swagger: + authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token} From 21a8cc04550290bd55209df6499fad39cd6e7e4c Mon Sep 17 00:00:00 2001 From: Peyman Date: Mon, 8 Jul 2024 17:09:46 +0330 Subject: [PATCH 8/9] Config logbook to show fewer logs (#459) Config logbook to show fewer logs --- .../app/controller/AccountantController.kt | 40 +--- .../app/controller/PairConfigController.kt | 53 +++++ .../src/main/resources/application.yml | 1 + .../walletproxy/config/WebClientConfig.kt | 3 +- .../walletproxy/proxy/WalletProxyImpl.kt | 5 +- .../walletproxy/proxy/WalletProxyImplTest.kt | 37 ++- .../src/main/resources/application.yml | 3 + .../ports/binance/config/WebClientConfig.kt | 2 +- .../api/ports/opex/config/WebClientConfig.kt | 2 +- .../bcgateway/app/config/WebClientConfig.kt | 4 +- .../app/controller/CurrencyController.kt | 55 +++-- .../src/main/resources/application.yml | 2 + .../opex/market/app/config/WebClientConfig.kt | 2 +- .../src/main/resources/application.yml | 2 + .../postgres/impl/MarketQueryHandlerImpl.kt | 214 ++++++++++-------- .../engine/core/engine/SimpleOrderBook.kt | 24 +- .../gateway/app/config/WebClientConfig.kt | 2 +- .../gateway/app/proxy/AccountantProxyImpl.kt | 4 +- .../opex/wallet/app/config/WebClientConfig.kt | 4 +- .../app/controller/BalanceController.kt | 6 +- .../app/controller/DepositController.kt | 70 +++--- .../app/controller/TransferController.kt | 150 ++++++------ .../src/main/resources/application.yml | 8 + 23 files changed, 389 insertions(+), 304 deletions(-) create mode 100644 accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/PairConfigController.kt diff --git a/accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/AccountantController.kt b/accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/AccountantController.kt index a90f12b4f..1be8924ea 100644 --- a/accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/AccountantController.kt +++ b/accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/AccountantController.kt @@ -20,8 +20,7 @@ import java.math.BigDecimal @RestController class AccountantController( val walletProxy: WalletProxy, - val financialActionLoader: FinancialActionLoader, - val pairConfigLoader: PairConfigLoader + val financialActionLoader: FinancialActionLoader ) { private val logger = LoggerFactory.getLogger(AccountantController::class.java) @@ -43,42 +42,5 @@ class AccountantController( BooleanResponse(false) } - @GetMapping("/config/{pair}/fee/{direction}-{userLevel}") - suspend fun fetchPairFeeConfig( - @PathVariable("pair") pair: String, - @PathVariable("direction") direction: OrderDirection, - @PathVariable("userLevel") level: String - ): PairFeeConfig { - return pairConfigLoader.load(pair, direction, level) - } - - @GetMapping("/config/{pair}/{direction}") - suspend fun fetchPairConfig( - @PathVariable("pair") pair: String, - @PathVariable("direction") direction: OrderDirection - ): PairConfig { - return pairConfigLoader.load(pair, direction) - } - - @GetMapping("/config/all") - suspend fun fetchPairConfigs(): List { - return pairConfigLoader.loadPairConfigs() - } - - @GetMapping("/config/fee") - suspend fun getFeeConfigs(): List { - return pairConfigLoader.loadPairFeeConfigs() - .map { PairFeeResponse(it.pairConfig.pair, it.direction, it.userLevel, it.makerFee, it.takerFee) } - } - @GetMapping("/config/fee/{pair}") - suspend fun getFeeConfig( - @PathVariable pair: String, - @RequestParam(required = false) direction: OrderDirection?, - @RequestParam(required = false) userLevel: String? - ): PairFeeResponse { - val fee = pairConfigLoader.loadPairFeeConfigs(pair, direction ?: OrderDirection.BID, userLevel ?: "*") - ?: throw OpexError.PairFeeNotFound.exception() - return PairFeeResponse(fee.pairConfig.pair, fee.direction, fee.userLevel, fee.makerFee, fee.takerFee) - } } \ No newline at end of file diff --git a/accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/PairConfigController.kt b/accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/PairConfigController.kt new file mode 100644 index 000000000..962218b17 --- /dev/null +++ b/accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/controller/PairConfigController.kt @@ -0,0 +1,53 @@ +package co.nilin.opex.accountant.app.controller + +import co.nilin.opex.accountant.app.data.PairFeeResponse +import co.nilin.opex.accountant.core.model.PairConfig +import co.nilin.opex.accountant.core.model.PairFeeConfig +import co.nilin.opex.accountant.core.spi.PairConfigLoader +import co.nilin.opex.common.OpexError +import co.nilin.opex.matching.engine.core.model.OrderDirection +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/config") +class PairConfigController(private val pairConfigLoader: PairConfigLoader) { + + @GetMapping("/{pair}/fee/{direction}-{userLevel}") + suspend fun fetchPairFeeConfig( + @PathVariable("pair") pair: String, + @PathVariable("direction") direction: OrderDirection, + @PathVariable("userLevel") level: String + ): PairFeeConfig { + return pairConfigLoader.load(pair, direction, level) + } + + @GetMapping("/{pair}/{direction}") + suspend fun fetchPairConfig( + @PathVariable("pair") pair: String, + @PathVariable("direction") direction: OrderDirection + ): PairConfig { + return pairConfigLoader.load(pair, direction) + } + + @GetMapping("/all") + suspend fun fetchPairConfigs(): List { + return pairConfigLoader.loadPairConfigs() + } + + @GetMapping("/fee") + suspend fun getFeeConfigs(): List { + return pairConfigLoader.loadPairFeeConfigs() + .map { PairFeeResponse(it.pairConfig.pair, it.direction, it.userLevel, it.makerFee, it.takerFee) } + } + + @GetMapping("/fee/{pair}") + suspend fun getFeeConfig( + @PathVariable pair: String, + @RequestParam(required = false) direction: OrderDirection?, + @RequestParam(required = false) userLevel: String? + ): PairFeeResponse { + val fee = pairConfigLoader.loadPairFeeConfigs(pair, direction ?: OrderDirection.BID, userLevel ?: "*") + ?: throw OpexError.PairFeeNotFound.exception() + return PairFeeResponse(fee.pairConfig.pair, fee.direction, fee.userLevel, fee.makerFee, fee.takerFee) + } +} \ No newline at end of file diff --git a/accountant/accountant-app/src/main/resources/application.yml b/accountant/accountant-app/src/main/resources/application.yml index 1d4c48dd3..fab5a83f7 100644 --- a/accountant/accountant-app/src/main/resources/application.yml +++ b/accountant/accountant-app/src/main/resources/application.yml @@ -87,6 +87,7 @@ logbook: - path: /auth** - path: /actuator/** - path: /swagger** + - path: /config/** logging: level: co.nilin: INFO diff --git a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt index dc33ddf7e..b559aa504 100644 --- a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt +++ b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/config/WebClientConfig.kt @@ -17,7 +17,8 @@ class WebClientConfig { @Bean fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } - return WebClient.builder().clientConnector(ReactorClientHttpConnector(client)) + return WebClient.builder() + //.clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt index caa1878b4..e37c32314 100644 --- a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt +++ b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt @@ -15,8 +15,9 @@ import java.math.BigDecimal @Component class WalletProxyImpl( - @Value("\${app.wallet.url}") val walletBaseUrl: String, - val webClient: WebClient + private val webClient: WebClient, + @Value("\${app.wallet.url}") + private val walletBaseUrl: String ) : WalletProxy { data class TransferBody( diff --git a/accountant/accountant-ports/accountant-wallet-proxy/src/test/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImplTest.kt b/accountant/accountant-ports/accountant-wallet-proxy/src/test/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImplTest.kt index 8663e7bff..ae186149d 100644 --- a/accountant/accountant-ports/accountant-wallet-proxy/src/test/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImplTest.kt +++ b/accountant/accountant-ports/accountant-wallet-proxy/src/test/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImplTest.kt @@ -20,7 +20,8 @@ class WalletProxyImplTest { lateinit var mockServer: MockServerClient val walletProxyImpl = WalletProxyImpl( - "http://localhost:8089", WebClient.builder().build() + WebClient.builder().build(), + "http://localhost:8089" ) val objectMapper = ObjectMapper() @@ -51,7 +52,16 @@ class WalletProxyImplTest { mockServer.`when`( request().withMethod("POST") .withPath("/v2/transfer/${amount}_$symbol/from/${senderUuid}_$senderWalletType/to/${receiverUuid}_$receiverWalletType") - .withBody(objectMapper.writeValueAsString(WalletProxyImpl.TransferBody(description, transferRef, transferCategory, additionalData))) + .withBody( + objectMapper.writeValueAsString( + WalletProxyImpl.TransferBody( + description, + transferRef, + transferCategory, + additionalData + ) + ) + ) ).respond( response() .withStatusCode(200) @@ -59,13 +69,32 @@ class WalletProxyImplTest { .withBody( objectMapper.writeValueAsString( TransferResult( - System.currentTimeMillis(), senderUuid, senderWalletType, amountObject, amountObject, amountObject, receiverUuid, receiverWalletType, amountObject + System.currentTimeMillis(), + senderUuid, + senderWalletType, + amountObject, + amountObject, + amountObject, + receiverUuid, + receiverWalletType, + amountObject ) ) ) ) runBlocking { - walletProxyImpl.transfer(symbol, senderWalletType, senderUuid, receiverWalletType, receiverUuid, amount, description, transferRef, transferCategory, additionalData) + walletProxyImpl.transfer( + symbol, + senderWalletType, + senderUuid, + receiverWalletType, + receiverUuid, + amount, + description, + transferRef, + transferCategory, + additionalData + ) } } diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index cda25dff9..594679726 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -77,6 +77,9 @@ logbook: - path: /auth** - path: /actuator/** - path: /swagger** + include: + - path: /v3/order + - path: /v1/capital/deposit/address logging: level: co.nilin: INFO diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt index 055d19033..57f5243a9 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/WebClientConfig.kt @@ -18,7 +18,7 @@ class WebClientConfig { fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt index c5e5aa387..7da7c0aad 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/WebClientConfig.kt @@ -18,7 +18,7 @@ class WebClientConfig { fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt index de3e8b5cf..8e4775d8b 100644 --- a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt +++ b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/WebClientConfig.kt @@ -21,7 +21,7 @@ class WebClientConfig { fun loadBalancedWebClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .exchangeStrategies( ExchangeStrategies.builder() @@ -36,7 +36,7 @@ class WebClientConfig { fun webClient(logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .exchangeStrategies( ExchangeStrategies.builder() .codecs { it.defaultCodecs().maxInMemorySize(20 * 1024 * 1024) } diff --git a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CurrencyController.kt b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CurrencyController.kt index 8f306dca8..2c550b9ea 100644 --- a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CurrencyController.kt +++ b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CurrencyController.kt @@ -22,7 +22,6 @@ class CurrencyController(val currencyHandler: CurrencyHandler) { return currencyHandler.fetchCurrencyInfo(currency) } - @PostMapping("/{currency}") suspend fun addCurrencyInfo( @PathVariable("currency") currencySymbol: String, @@ -30,19 +29,19 @@ class CurrencyController(val currencyHandler: CurrencyHandler) { ): CurrencyImplementation? { addCurrencyRequest.currencySymbol = currencySymbol with(addCurrencyRequest) { - - return currencyHandler.addCurrencyImplementationV2(this.currencySymbol!!, - this.implementationSymbol, - this.currencyName, - this.chain, - this.tokenName, - this.tokenAddress, - this.isToken!!, - this.withdrawFee, - this.minimumWithdraw, - this.isWithdrawEnabled!!, - this.decimal - ) + return currencyHandler.addCurrencyImplementationV2( + this.currencySymbol, + implementationSymbol, + currencyName, + chain, + tokenName, + tokenAddress, + isToken!!, + withdrawFee, + minimumWithdraw, + isWithdrawEnabled!!, + decimal + ) } } @@ -50,22 +49,22 @@ class CurrencyController(val currencyHandler: CurrencyHandler) { suspend fun updateCurrencyInfo( @PathVariable("currency") currencySymbol: String, @RequestBody addCurrencyRequest: AddCurrencyRequest - ):CurrencyImplementation? { + ): CurrencyImplementation? { addCurrencyRequest.currencySymbol = currencySymbol with(addCurrencyRequest) { - - return currencyHandler.updateCurrencyImplementation(this.currencySymbol!!, - this.implementationSymbol, - this.currencyName, - this.newChain, - this.tokenName, - this.tokenAddress, - this.isToken!!, - this.withdrawFee, - this.minimumWithdraw, - this.isWithdrawEnabled!!, - this.decimal, - this.chain + return currencyHandler.updateCurrencyImplementation( + this.currencySymbol, + implementationSymbol, + currencyName, + newChain, + tokenName, + tokenAddress, + isToken!!, + withdrawFee, + minimumWithdraw, + isWithdrawEnabled!!, + decimal, + chain ) } } diff --git a/bc-gateway/bc-gateway-app/src/main/resources/application.yml b/bc-gateway/bc-gateway-app/src/main/resources/application.yml index 7248b254a..9bc57d70d 100644 --- a/bc-gateway/bc-gateway-app/src/main/resources/application.yml +++ b/bc-gateway/bc-gateway-app/src/main/resources/application.yml @@ -79,6 +79,8 @@ logbook: - path: /auth** - path: /actuator/** - path: /swagger** + include: + - path: /v1/address** logging: level: org.apache.kafka: ERROR diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt index 8c59fc3fe..3ac945a3e 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/WebClientConfig.kt @@ -19,7 +19,7 @@ class WebClientConfig { fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/market/market-app/src/main/resources/application.yml b/market/market-app/src/main/resources/application.yml index 2e1f1510e..d241ac99a 100644 --- a/market/market-app/src/main/resources/application.yml +++ b/market/market-app/src/main/resources/application.yml @@ -81,6 +81,8 @@ logbook: - path: /auth** - path: /actuator/** - path: /swagger** + include: + - path: /v1/order/** logging: level: co.nilin: INFO diff --git a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt index e3dba3aed..1d791a833 100644 --- a/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt +++ b/market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/impl/MarketQueryHandlerImpl.kt @@ -1,6 +1,7 @@ package co.nilin.opex.market.ports.postgres.impl import co.nilin.opex.common.utils.Interval +import co.nilin.opex.common.utils.hours import co.nilin.opex.common.utils.minutes import co.nilin.opex.market.core.inout.* import co.nilin.opex.market.core.spi.MarketQueryHandler @@ -17,9 +18,8 @@ import kotlinx.coroutines.reactive.awaitFirst import kotlinx.coroutines.reactive.awaitFirstOrElse import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactor.awaitSingleOrNull -import org.springframework.data.domain.PageRequest -import org.springframework.data.domain.Sort import org.springframework.stereotype.Component +import java.lang.StringBuilder import java.math.BigDecimal import java.time.Instant import java.time.LocalDateTime @@ -28,10 +28,10 @@ import java.util.* @Component class MarketQueryHandlerImpl( - private val orderRepository: OrderRepository, - private val tradeRepository: TradeRepository, - private val orderStatusRepository: OrderStatusRepository, - private val redisCacheHelper: RedisCacheHelper + private val orderRepository: OrderRepository, + private val tradeRepository: TradeRepository, + private val orderStatusRepository: OrderStatusRepository, + private val redisCacheHelper: RedisCacheHelper ) : MarketQueryHandler { //TODO merge order and status fetching in query @@ -39,9 +39,9 @@ class MarketQueryHandlerImpl( override suspend fun getTradeTickerData(interval: Interval): List { return redisCacheHelper.getOrElse("tradeTickerData:${interval.label}", 2.minutes()) { tradeRepository.tradeTicker(interval.getLocalDateTime()) - .collectList() - .awaitFirstOrElse { emptyList() } - .map { it.asPriceChangeResponse(Date().time, interval.getTime()) } + .collectList() + .awaitFirstOrElse { emptyList() } + .map { it.asPriceChangeResponse(Date().time, interval.getTime()) } } } @@ -49,31 +49,31 @@ class MarketQueryHandlerImpl( val cacheId = "tradeTickerData:$symbol:${interval.label}" return redisCacheHelper.getOrElse(cacheId, 2.minutes()) { tradeRepository.tradeTickerBySymbol(symbol, interval.getLocalDateTime()) - .awaitFirstOrNull() - ?.asPriceChangeResponse(Date().time, interval.getTime()) + .awaitFirstOrNull() + ?.asPriceChangeResponse(Date().time, interval.getTime()) } } override suspend fun openBidOrders(symbol: String, limit: Int): List { return orderRepository.findBySymbolAndDirectionAndStatusSortDescendingByPrice( - symbol, - OrderDirection.BID, - limit, - listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) + symbol, + OrderDirection.BID, + limit, + listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) ).collectList() - .awaitFirstOrElse { emptyList() } - .map { OrderBook(it.price, it.quantity) } + .awaitFirstOrElse { emptyList() } + .map { OrderBook(it.price, it.quantity) } } override suspend fun openAskOrders(symbol: String, limit: Int): List { return orderRepository.findBySymbolAndDirectionAndStatusSortAscendingByPrice( - symbol, - OrderDirection.ASK, - limit, - listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) + symbol, + OrderDirection.ASK, + limit, + listOf(OrderStatus.NEW.code, OrderStatus.PARTIALLY_FILLED.code) ).collectList() - .awaitFirstOrElse { emptyList() } - .map { OrderBook(it.price, it.quantity) } + .awaitFirstOrElse { emptyList() } + .map { OrderBook(it.price, it.quantity) } } // @Cacheable does not support suspended functions. Spring 6.1 required. @@ -94,28 +94,28 @@ class MarketQueryHandlerImpl( return recentTradesCache.toList() return tradeRepository.findBySymbolSortDescendingByCreateDate(symbol, limit) - .map { - val takerOrder = orderRepository.findByOuid(it.takerOuid).awaitFirst() - val makerOrder = orderRepository.findByOuid(it.makerOuid).awaitFirst() - val isMakerBuyer = makerOrder.direction == OrderDirection.BID - MarketTrade( - it.symbol, - it.baseAsset, - it.quoteAsset, - it.tradeId, - it.matchedPrice, - it.matchedQuantity, - if (isMakerBuyer) - makerOrder.quoteQuantity!! - else - takerOrder.quoteQuantity!!, - Date.from(it.createDate.atZone(ZoneId.systemDefault()).toInstant()), - true, - isMakerBuyer - ) - }.toList() - .onEach { redisCacheHelper.putListItem(cacheKey, it) } - .also { redisCacheHelper.setExpiration(cacheKey, 60.minutes()) } + .map { + val takerOrder = orderRepository.findByOuid(it.takerOuid).awaitFirst() + val makerOrder = orderRepository.findByOuid(it.makerOuid).awaitFirst() + val isMakerBuyer = makerOrder.direction == OrderDirection.BID + MarketTrade( + it.symbol, + it.baseAsset, + it.quoteAsset, + it.tradeId, + it.matchedPrice, + it.matchedQuantity, + if (isMakerBuyer) + makerOrder.quoteQuantity!! + else + takerOrder.quoteQuantity!!, + Date.from(it.createDate.atZone(ZoneId.systemDefault()).toInstant()), + true, + isMakerBuyer + ) + }.toList() + .onEach { redisCacheHelper.putListItem(cacheKey, it) } + .also { redisCacheHelper.setExpiration(cacheKey, 60.minutes()) } } override suspend fun lastPrice(symbol: String?): List { @@ -132,17 +132,17 @@ class MarketQueryHandlerImpl( val id = symbols.joinToString { it } return redisCacheHelper.getOrElse("bestPricesForSymbols:$id", 1.minutes()) { tradeRepository.bestAskAndBidPrice(symbols) - .collectList() - .awaitFirstOrElse { emptyList() } + .collectList() + .awaitFirstOrElse { emptyList() } } } override suspend fun getCandleInfo( - symbol: String, - interval: String, - startTime: Long?, - endTime: Long?, - limit: Int + symbol: String, + interval: String, + startTime: Long?, + endTime: Long?, + limit: Int ): List { val st = if (startTime == null) tradeRepository.findFirstByCreateDate().awaitFirstOrNull()?.createDate ?: LocalDateTime.now() @@ -159,66 +159,71 @@ class MarketQueryHandlerImpl( } return tradeRepository.candleData(symbol, interval, st, et, limit) - .collectList() - .awaitFirstOrElse { emptyList() } - .map { - CandleData( - it.openTime, - it.closeTime, - it.open ?: BigDecimal.ZERO, - it.close ?: BigDecimal.ZERO, - it.high ?: BigDecimal.ZERO, - it.low ?: BigDecimal.ZERO, - it.volume ?: BigDecimal.ZERO, - BigDecimal.ZERO, - it.trades, - BigDecimal.ZERO, - BigDecimal.ZERO - ) - } + .collectList() + .awaitFirstOrElse { emptyList() } + .map { + CandleData( + it.openTime, + it.closeTime, + it.open ?: BigDecimal.ZERO, + it.close ?: BigDecimal.ZERO, + it.high ?: BigDecimal.ZERO, + it.low ?: BigDecimal.ZERO, + it.volume ?: BigDecimal.ZERO, + BigDecimal.ZERO, + it.trades, + BigDecimal.ZERO, + BigDecimal.ZERO + ) + } } override suspend fun numberOfActiveUsers(interval: Interval): Long { - return redisCacheHelper.getOrElse("activeUsers:${interval.label}", 5.minutes()) { - orderRepository.countUsersWhoMadeOrder(interval.getLocalDateTime()).singleOrNull() ?: 0L + return redisCacheHelper.getOrElse("activeUsers:${interval.label}", 1.hours()) { + //TODO remove times(10) + orderRepository.countUsersWhoMadeOrder(interval.getLocalDateTime()) + .singleOrNull() + ?.times(10)?.approximate() ?: 0L } } override suspend fun numberOfTrades(interval: Interval, pair: String?): Long { return if (pair != null) - redisCacheHelper.getOrElse("tradeCount:$pair:${interval.label}", 5.minutes()) { - tradeRepository.countBySymbolNewerThan(interval.getLocalDateTime(), pair).singleOrNull() ?: 0 + redisCacheHelper.getOrElse("tradeCount:$pair:${interval.label}", 1.hours()) { + tradeRepository.countBySymbolNewerThan(interval.getLocalDateTime(), pair).singleOrNull()?.approximate() + ?: 0 } else - redisCacheHelper.getOrElse("tradeCount:${interval.label}", 5.minutes()) { - tradeRepository.countNewerThan(interval.getLocalDateTime()).singleOrNull() ?: 0 + redisCacheHelper.getOrElse("tradeCount:${interval.label}", 1.hours()) { + tradeRepository.countNewerThan(interval.getLocalDateTime()).singleOrNull()?.approximate() ?: 0 } } override suspend fun numberOfOrders(interval: Interval, pair: String?): Long { return if (pair != null) - redisCacheHelper.getOrElse("orderCount:$pair:${interval.label}", 5.minutes()) { - orderRepository.countBySymbolNewerThan(interval.getLocalDateTime(), pair).singleOrNull() ?: 0 + redisCacheHelper.getOrElse("orderCount:$pair:${interval.label}", 1.hours()) { + orderRepository.countBySymbolNewerThan(interval.getLocalDateTime(), pair).singleOrNull()?.approximate() + ?: 0 } else - redisCacheHelper.getOrElse("orderCount:${interval.label}", 5.minutes()) { - orderRepository.countNewerThan(interval.getLocalDateTime()).singleOrNull() ?: 0 + redisCacheHelper.getOrElse("orderCount:${interval.label}", 1.hours()) { + orderRepository.countNewerThan(interval.getLocalDateTime()).singleOrNull()?.approximate() ?: 0 } } override suspend fun mostIncreasePrice(interval: Interval, limit: Int): List { return redisCacheHelper.getOrElse("priceIncrease:${interval.label}", 1.minutes()) { tradeRepository.findByMostIncreasedPrice(interval.getLocalDateTime(), limit) - .collectList() - .awaitFirstOrElse { emptyList() } + .collectList() + .awaitFirstOrElse { emptyList() } }.take(limit) } override suspend fun mostDecreasePrice(interval: Interval, limit: Int): List { return redisCacheHelper.getOrElse("priceDecrease:${interval.label}", 1.minutes()) { tradeRepository.findByMostDecreasedPrice(interval.getLocalDateTime(), limit) - .collectList() - .awaitFirstOrElse { emptyList() } + .collectList() + .awaitFirstOrElse { emptyList() } }.take(limit) } @@ -235,25 +240,34 @@ class MarketQueryHandlerImpl( } private fun TradeTickerData.asPriceChangeResponse(openTime: Long, closeTime: Long) = PriceChange( - symbol, - priceChange ?: BigDecimal.ZERO, - priceChangePercent ?: BigDecimal.ZERO, - weightedAvgPrice ?: BigDecimal.ZERO, - lastPrice ?: BigDecimal.ZERO, - lastQty ?: BigDecimal.ZERO, - bidPrice ?: BigDecimal.ZERO, - askPrice ?: BigDecimal.ZERO, - openPrice ?: BigDecimal.ZERO, - highPrice ?: BigDecimal.ZERO, - lowPrice ?: BigDecimal.ZERO, - volume ?: BigDecimal.ZERO, - openTime, - closeTime, - firstId ?: -1, - lastId ?: -1, - count ?: 0 + symbol, + priceChange ?: BigDecimal.ZERO, + priceChangePercent ?: BigDecimal.ZERO, + weightedAvgPrice ?: BigDecimal.ZERO, + lastPrice ?: BigDecimal.ZERO, + lastQty ?: BigDecimal.ZERO, + bidPrice ?: BigDecimal.ZERO, + askPrice ?: BigDecimal.ZERO, + openPrice ?: BigDecimal.ZERO, + highPrice ?: BigDecimal.ZERO, + lowPrice ?: BigDecimal.ZERO, + volume ?: BigDecimal.ZERO, + openTime, + closeTime, + firstId ?: -1, + lastId ?: -1, + count ?: 0 ) + private fun Long.approximate(): Long { + if (this < 10) + return this + + val str = toString() + val builder = StringBuilder(str.substring(0, 1)) + repeat(str.length - 1) { builder.append("0") } + return builder.toString().toLong() + } } diff --git a/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt b/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt index 7803d365c..5475734ee 100644 --- a/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt +++ b/matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/engine/SimpleOrderBook.kt @@ -162,10 +162,14 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { } override fun handleCancelCommand(orderCommand: OrderCancelCommand) { - logger.info("********************* order cancel **********************") - logger.info("** order id: ${orderCommand.ouid}") - logger.info("*********************************************************") - println() + logger.info( + """ + ---- CANCEL ${orderCommand.pair.leftSideName}-${orderCommand.pair.rightSideName} ---- + - order id: ${orderCommand.ouid} + ******************************************** + + """.trimIndent() + ) val simpleOrder = orders.entries.find { it.value.ouid == orderCommand.ouid } val order = simpleOrder?.value @@ -583,11 +587,11 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { private fun logNewOrder(orderCommand: OrderCreateCommand) { logger.info( """ - ++++ NEW ${orderCommand.pair.leftSideName}-${orderCommand.pair.rightSideName} - - ouid: ${orderCommand.ouid}") - - price: ${orderCommand.price}") - - quantity: ${orderCommand.quantity}") - - direction: ${orderCommand.direction}") + ++++ NEW ${orderCommand.pair.leftSideName}-${orderCommand.pair.rightSideName} ++++ + - ouid: ${orderCommand.ouid} + - price: ${orderCommand.price} + - quantity: ${orderCommand.quantity} + - direction: ${orderCommand.direction} ******************************************** """.trimIndent() @@ -597,7 +601,7 @@ class SimpleOrderBook(val pair: Pair, var replayMode: Boolean) : OrderBook { private fun logCurrentState() { logger.info( """ - ==== STATE ${pair.leftSideName}-${pair.rightSideName} + ==== STATE ${pair.leftSideName}-${pair.rightSideName} ==== - askOrders size: ${askOrders.entriesList().size} - bidOrders size: ${bidOrders.entriesList().size} - orders size: ${orders.size} diff --git a/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt b/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt index dc4ccef9d..0fd266d83 100644 --- a/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt +++ b/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/WebClientConfig.kt @@ -18,7 +18,7 @@ class WebClientConfig { fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory, logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } diff --git a/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/proxy/AccountantProxyImpl.kt b/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/proxy/AccountantProxyImpl.kt index b993c247c..4ec038f69 100644 --- a/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/proxy/AccountantProxyImpl.kt +++ b/matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/proxy/AccountantProxyImpl.kt @@ -14,8 +14,8 @@ import java.math.BigDecimal @Component class AccountantProxyImpl( @Value("\${app.accountant.url}") - val accountantBaseUrl: String, - val webClient: WebClient + private val accountantBaseUrl: String, + private val webClient: WebClient ) : AccountantApiProxy { override suspend fun canCreateOrder(uuid: String, symbol: String, value: BigDecimal): Boolean { diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt index 8302c6ae0..ffc4824df 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt @@ -25,7 +25,7 @@ class WebClientConfig { ): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .build() } @@ -36,7 +36,7 @@ class WebClientConfig { fun webClient(logbook: Logbook): WebClient { val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() - .clientConnector(ReactorClientHttpConnector(client)) + //.clientConnector(ReactorClientHttpConnector(client)) .build() } diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt index 4f8dab5e3..e2d65930d 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/BalanceController.kt @@ -16,11 +16,11 @@ import java.security.Principal @RestController class BalanceController( - val walletManager: WalletManager, val walletOwnerManager: WalletOwnerManager, val currencyService: CurrencyService + private val walletManager: WalletManager, + private val walletOwnerManager: WalletOwnerManager, + private val currencyService: CurrencyService ) { - private val logger = LoggerFactory.getLogger(BalanceController::class.java) - data class BalanceResponse(val balance: BigDecimal) @GetMapping("/balanceOf/wallet_type/{wallet_type}/currency/{currency}") diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt index 2e8ac50b6..18381097b 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositController.kt @@ -22,59 +22,59 @@ import java.time.ZoneId @RestController @RequestMapping("/v1/deposit") -class DepositController(private val depositPersister: DepositPersister, - private val transferService: TransferService) { - +class DepositController( + private val depositPersister: DepositPersister, + private val transferService: TransferService +) { @PostMapping("/{uuid}/history") suspend fun getDepositTransactionsForUser( - @PathVariable("uuid") uuid: String, - @RequestBody request: TransactionRequest, - @CurrentSecurityContext securityContext: SecurityContext + @PathVariable("uuid") uuid: String, + @RequestBody request: TransactionRequest, + @CurrentSecurityContext securityContext: SecurityContext ): Deposits { if (securityContext.authentication.name != uuid) throw OpexError.Forbidden.exception() + return depositPersister.findDepositHistory( - uuid, - request.coin, - request.startTime?.let { - LocalDateTime.ofInstant(Instant.ofEpochMilli(request.startTime), ZoneId.systemDefault()) - } - ?: null, - request.endTime?.let { - LocalDateTime.ofInstant(Instant.ofEpochMilli(request.endTime), ZoneId.systemDefault()) - } ?: null, - request.limit!!, - request.offset!!, - request.ascendingByTime + uuid, + request.coin, + request.startTime?.let { + LocalDateTime.ofInstant(Instant.ofEpochMilli(request.startTime), ZoneId.systemDefault()) + }, + request.endTime?.let { + LocalDateTime.ofInstant(Instant.ofEpochMilli(request.endTime), ZoneId.systemDefault()) + }, + request.limit!!, + request.offset!!, + request.ascendingByTime ) } @PostMapping("/manually/{amount}_{symbol}/{receiverUuid}") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ }", - mediaType = "application/json" - ) + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ }", + mediaType = "application/json" ) + ) ) suspend fun depositManually( - @PathVariable("symbol") symbol: String, - @PathVariable("receiverUuid") receiverUuid: String, - @PathVariable("amount") amount: BigDecimal, - @RequestBody request: ManualTransferRequest, - @CurrentSecurityContext securityContext: SecurityContext + @PathVariable("symbol") symbol: String, + @PathVariable("receiverUuid") receiverUuid: String, + @PathVariable("amount") amount: BigDecimal, + @RequestBody request: ManualTransferRequest, + @CurrentSecurityContext securityContext: SecurityContext ): TransferResult { - - return transferService.depositManually(symbol, receiverUuid, - securityContext.authentication.name, amount, request) + return transferService.depositManually( + symbol, receiverUuid, + securityContext.authentication.name, amount, request + ) } - - } diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt index 00626a2a3..9e420bdb3 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt @@ -1,93 +1,91 @@ package co.nilin.opex.wallet.app.controller -import co.nilin.opex.wallet.app.dto.ManualTransferRequest import co.nilin.opex.wallet.app.dto.TransferRequest import co.nilin.opex.wallet.app.service.TransferService import co.nilin.opex.wallet.core.inout.TransferResult import io.swagger.annotations.ApiResponse import io.swagger.annotations.Example import io.swagger.annotations.ExampleProperty -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* import java.math.BigDecimal @RestController class TransferController(private val transferService: TransferService) { + data class TransferBody( - val description: String?, - val transferRef: String?, - val transferCategory: String, - val additionalData: Map? + val description: String?, + val transferRef: String?, + val transferCategory: String, + val additionalData: Map? ) @PostMapping("/v2/transfer/{amount}_{symbol}/from/{senderUuid}_{senderWalletType}/to/{receiverUuid}_{receiverWalletType}") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ }", - mediaType = "application/json" - ) + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ }", + mediaType = "application/json" ) + ) ) suspend fun transfer( - @PathVariable("symbol") symbol: String, - @PathVariable("senderWalletType") senderWalletType: String, - @PathVariable("senderUuid") senderUuid: String, - @PathVariable("receiverWalletType") receiverWalletType: String, - @PathVariable("receiverUuid") receiverUuid: String, - @PathVariable("amount") amount: BigDecimal, - @RequestBody transferBody: TransferBody + @PathVariable("symbol") symbol: String, + @PathVariable("senderWalletType") senderWalletType: String, + @PathVariable("senderUuid") senderUuid: String, + @PathVariable("receiverWalletType") receiverWalletType: String, + @PathVariable("receiverUuid") receiverUuid: String, + @PathVariable("amount") amount: BigDecimal, + @RequestBody transferBody: TransferBody ): TransferResult { return transferService.transfer( - symbol, - senderWalletType, - senderUuid, - receiverWalletType, - receiverUuid, - amount, - transferBody.description, - transferBody.transferRef, - transferBody.transferCategory, - transferBody.additionalData + symbol, + senderWalletType, + senderUuid, + receiverWalletType, + receiverUuid, + amount, + transferBody.description, + transferBody.transferRef, + transferBody.transferCategory, + transferBody.additionalData ) } @PostMapping("/transfer/{amount}_{symbol}/from/{senderUuid}_{senderWalletType}/to/{receiverUuid}_{receiverWalletType}") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ }", - mediaType = "application/json" - ) + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ }", + mediaType = "application/json" ) + ) ) suspend fun transfer( - @PathVariable("symbol") symbol: String, - @PathVariable("senderWalletType") senderWalletType: String, - @PathVariable("senderUuid") senderUuid: String, - @PathVariable("receiverWalletType") receiverWalletType: String, - @PathVariable("receiverUuid") receiverUuid: String, - @PathVariable("amount") amount: BigDecimal, - @RequestParam("description") description: String?, - @RequestParam("transferRef") transferRef: String?, - @RequestBody transferBody: TransferBody + @PathVariable("symbol") symbol: String, + @PathVariable("senderWalletType") senderWalletType: String, + @PathVariable("senderUuid") senderUuid: String, + @PathVariable("receiverWalletType") receiverWalletType: String, + @PathVariable("receiverUuid") receiverUuid: String, + @PathVariable("amount") amount: BigDecimal, + @RequestParam("description") description: String?, + @RequestParam("transferRef") transferRef: String?, + @RequestBody transferBody: TransferBody ): TransferResult { return transferService.transfer( - symbol, - senderWalletType, - senderUuid, - receiverWalletType, - receiverUuid, - amount, - description, - transferRef, - transferBody.transferCategory, - transferBody.additionalData + symbol, + senderWalletType, + senderUuid, + receiverWalletType, + receiverUuid, + amount, + description, + transferRef, + transferBody.transferCategory, + transferBody.additionalData ) } @@ -99,25 +97,33 @@ class TransferController(private val transferService: TransferService) { @PostMapping("/deposit/{amount}_{chain}_{symbol}/{receiverUuid}_{receiverWalletType}") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ }", - mediaType = "application/json" - ) + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ }", + mediaType = "application/json" ) + ) ) suspend fun deposit( - @PathVariable("symbol") symbol: String, - @PathVariable("receiverUuid") receiverUuid: String, - @PathVariable("receiverWalletType") receiverWalletType: String, - @PathVariable("amount") amount: BigDecimal, - @RequestParam("description") description: String?, - @RequestParam("transferRef") transferRef: String?, - @PathVariable("chain") chain: String? + @PathVariable("symbol") symbol: String, + @PathVariable("receiverUuid") receiverUuid: String, + @PathVariable("receiverWalletType") receiverWalletType: String, + @PathVariable("amount") amount: BigDecimal, + @RequestParam("description") description: String?, + @RequestParam("transferRef") transferRef: String?, + @PathVariable("chain") chain: String? ): TransferResult { - return transferService.deposit(symbol, receiverUuid, receiverWalletType, amount, description, transferRef, chain) + return transferService.deposit( + symbol, + receiverUuid, + receiverWalletType, + amount, + description, + transferRef, + chain + ) } } diff --git a/wallet/wallet-app/src/main/resources/application.yml b/wallet/wallet-app/src/main/resources/application.yml index da17a6608..70479e183 100644 --- a/wallet/wallet-app/src/main/resources/application.yml +++ b/wallet/wallet-app/src/main/resources/application.yml @@ -80,6 +80,14 @@ logbook: - path: /auth** - path: /actuator/** - path: /swagger** + include: + - path: /admin/withdraw/** + methods: + - POST + - path: /v1/deposit/manually/** + - path: /v2/transfer/** + - path: /transfer/** + - path: /deposit/** logging: level: root: INFO From 361399cbfe10514c676b9bd74b30dff414357af4 Mon Sep 17 00:00:00 2001 From: Peyman Date: Mon, 8 Jul 2024 18:32:43 +0330 Subject: [PATCH 9/9] Add even more services to log --- .../walletproxy/proxy/WalletProxyImpl.kt | 2 +- .../src/main/resources/application.yml | 8 ++ .../app/controller/AddressController.kt | 22 +++--- .../src/main/resources/application.yml | 11 ++- .../app/controller/UserDataController.kt | 14 ++-- .../controller/AdvancedTransferController.kt | 77 +++++++++++-------- .../app/controller/InquiryController.kt | 2 + .../app/controller/TransferController.kt | 1 - .../src/main/resources/application.yml | 14 ++++ 9 files changed, 99 insertions(+), 52 deletions(-) diff --git a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt index e37c32314..5bcd13cd2 100644 --- a/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt +++ b/accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/proxy/WalletProxyImpl.kt @@ -64,7 +64,7 @@ class WalletProxyImpl( override suspend fun canFulfil(symbol: String, walletType: String, uuid: String, amount: BigDecimal): Boolean { return webClient.get() - .uri("$walletBaseUrl/$uuid/wallet_type/$walletType/can_withdraw/${amount}_$symbol") + .uri("$walletBaseUrl/inquiry/$uuid/wallet_type/$walletType/can_withdraw/${amount}_$symbol") .header("Content-Type", "application/json") .retrieve() .onStatus({ t -> t.isError }, { it.createException() }) diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 594679726..d469fa840 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -79,7 +79,15 @@ logbook: - path: /swagger** include: - path: /v3/order + methods: + - POST + - PUT - path: /v1/capital/deposit/address + - path: /v1/api-key + methods: + - POST + - PUT + - DELETE logging: level: co.nilin: INFO diff --git a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/AddressController.kt b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/AddressController.kt index 08b31c749..e5510a1dc 100644 --- a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/AddressController.kt +++ b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/AddressController.kt @@ -25,26 +25,28 @@ import java.util.stream.Collectors @RestController @RequestMapping("/v1/address") class AddressController( - private val assignAddressService: AssignAddressService, - private val reservedAddressHandler: ReservedAddressHandler, - private val addressTypeHandler: AddressTypeHandler + private val assignAddressService: AssignAddressService, + private val reservedAddressHandler: ReservedAddressHandler, + private val addressTypeHandler: AddressTypeHandler ) { data class AssignAddressRequest(val uuid: String, val currency: String, val chain: String) data class AssignAddressResponse(val addresses: List) @PostMapping("/assign") - suspend fun assignAddress(@RequestBody assignAddressRequest: AssignAddressRequest, - @CurrentSecurityContext securityContext: SecurityContext?): AssignAddressResponse { + suspend fun assignAddress( + @RequestBody assignAddressRequest: AssignAddressRequest, + @CurrentSecurityContext securityContext: SecurityContext? + ): AssignAddressResponse { if (!(securityContext == null || securityContext.authentication.name == assignAddressRequest.uuid)) throw OpexError.Forbidden.exception() val assignedAddress = assignAddressService.assignAddress( - assignAddressRequest.uuid, - Currency(assignAddressRequest.currency, assignAddressRequest.currency), - assignAddressRequest.chain + assignAddressRequest.uuid, + Currency(assignAddressRequest.currency, assignAddressRequest.currency), + assignAddressRequest.chain ) - return AssignAddressResponse(assignedAddress); - // stream().map { it -> + return AssignAddressResponse(assignedAddress); + // stream().map { it -> // it.apply { // this.expTime = this.expTime?.atZone(ZoneId.systemDefault())?.withZoneSameInstant(ZoneId.of("Asia/Tehran"))?.toLocalDateTime() // this.assignedDate = this.assignedDate?.atZone(ZoneId.systemDefault())?.withZoneSameInstant(ZoneId.of("Asia/Tehran"))?.toLocalDateTime() diff --git a/bc-gateway/bc-gateway-app/src/main/resources/application.yml b/bc-gateway/bc-gateway-app/src/main/resources/application.yml index 9bc57d70d..4b7ebd796 100644 --- a/bc-gateway/bc-gateway-app/src/main/resources/application.yml +++ b/bc-gateway/bc-gateway-app/src/main/resources/application.yml @@ -80,7 +80,16 @@ logbook: - path: /actuator/** - path: /swagger** include: - - path: /v1/address** + - path: /v1/address/assign** + - path: /admin/** + methods: + - POST + - PUT + - path: /currency/** + methods: + - POST + - PUT + - path: /wallet-sync** logging: level: org.apache.kafka: ERROR diff --git a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt index fe3cf5cd5..aa19ab1b1 100644 --- a/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt +++ b/market/market-app/src/main/kotlin/co/nilin/opex/market/app/controller/UserDataController.kt @@ -24,9 +24,9 @@ class UserDataController(private val userQueryHandler: UserQueryHandler) { @GetMapping("/{uuid}/orders/{symbol}/open") suspend fun getUserOpenOrders( - @PathVariable uuid: String, - @PathVariable symbol: String, - @RequestParam limit: Int + @PathVariable uuid: String, + @PathVariable symbol: String, + @RequestParam limit: Int ): List { return userQueryHandler.openOrders(uuid, symbol, limit) } @@ -42,9 +42,11 @@ class UserDataController(private val userQueryHandler: UserQueryHandler) { } @PostMapping("/tx/{user}/history") - suspend fun getTxOfTrades(@PathVariable user: String, - @RequestBody transactionRequest: TransactionRequest, - @CurrentSecurityContext securityContext: SecurityContext): TransactionResponse? { + suspend fun getTxOfTrades( + @PathVariable user: String, + @RequestBody transactionRequest: TransactionRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): TransactionResponse? { if (securityContext.authentication.name != user) throw OpexError.Forbidden.exception() return userQueryHandler.txOfTrades(transactionRequest.apply { owner = user }) diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt index 5b7f7e38d..540e37769 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt @@ -25,38 +25,38 @@ class AdvancedTransferController { @GetMapping("/v3/amount/{amount}_{symbol}/{destSymbol}") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ \"destAmount\": \"111\"}", - mediaType = "application/json" - ) + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ \"destAmount\": \"111\"}", + mediaType = "application/json" ) + ) ) suspend fun calculateDestinationAmount( - @PathVariable("symbol") symbol: String, - @PathVariable("amount") amount: BigDecimal, - @PathVariable("destSymbol") destSymbol: String, + @PathVariable("symbol") symbol: String, + @PathVariable("amount") amount: BigDecimal, + @PathVariable("destSymbol") destSymbol: String, ): TransferPreEvaluateResponse { return TransferPreEvaluateResponse(transferService.calculateDestinationAmount(symbol, amount, destSymbol)) } @PostMapping("/v3/transfer/reserve") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{ \"reserveUuid\": \"214234\"," + - " \"guaranteedDestAmount\": \"1000\"}", - mediaType = "application/json" - ) + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{ \"reserveUuid\": \"214234\"," + + " \"guaranteedDestAmount\": \"1000\"}", + mediaType = "application/json" ) + ) ) suspend fun reserve( - @RequestBody request: TransferReserveRequest, - @CurrentSecurityContext securityContext: SecurityContext? + @RequestBody request: TransferReserveRequest, + @CurrentSecurityContext securityContext: SecurityContext? ): ReservedTransferResponse { securityContext?.let { if (request.senderUuid != it.authentication.name) @@ -64,28 +64,39 @@ class AdvancedTransferController { request.senderUuid = it.authentication.name } return transferService.reserveTransfer( - request.sourceAmount, request.sourceSymbol, request.destSymbol, request.senderUuid!!, request.senderWalletType, request.receiverUuid, request.receiverWalletType + request.sourceAmount, + request.sourceSymbol, + request.destSymbol, + request.senderUuid!!, + request.senderWalletType, + request.receiverUuid, + request.receiverWalletType ) } @PostMapping("/v3/transfer/{reserveUuid}") @ApiResponse( - message = "OK", - code = 200, - examples = Example( - ExampleProperty( - value = "{}", - mediaType = "application/json" - ) + message = "OK", + code = 200, + examples = Example( + ExampleProperty( + value = "{}", + mediaType = "application/json" ) + ) ) suspend fun finalizeTransfer( - @PathVariable("reserveUuid") reserveUuid: String, - @RequestParam("description") description: String?, - @RequestParam("transferRef") transferRef: String?, - @CurrentSecurityContext securityContext: SecurityContext? + @PathVariable("reserveUuid") reserveUuid: String, + @RequestParam("description") description: String?, + @RequestParam("transferRef") transferRef: String?, + @CurrentSecurityContext securityContext: SecurityContext? ): TransferResult { - return transferService.advanceTransfer(reserveUuid, description, transferRef, securityContext?.authentication?.name) + return transferService.advanceTransfer( + reserveUuid, + description, + transferRef, + securityContext?.authentication?.name + ) } } \ No newline at end of file diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt index d1560391b..0f10578c3 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/InquiryController.kt @@ -14,10 +14,12 @@ import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import java.math.BigDecimal @RestController +@RequestMapping("/inquiry") class InquiryController( private val walletManager: WalletManager, private val walletOwnerManager: WalletOwnerManager, diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt index 9e420bdb3..547a16216 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TransferController.kt @@ -94,7 +94,6 @@ class TransferController(private val transferService: TransferService) { transferService.batchTransfer(request) } - @PostMapping("/deposit/{amount}_{chain}_{symbol}/{receiverUuid}_{receiverWalletType}") @ApiResponse( message = "OK", diff --git a/wallet/wallet-app/src/main/resources/application.yml b/wallet/wallet-app/src/main/resources/application.yml index 70479e183..6b8d92895 100644 --- a/wallet/wallet-app/src/main/resources/application.yml +++ b/wallet/wallet-app/src/main/resources/application.yml @@ -84,10 +84,24 @@ logbook: - path: /admin/withdraw/** methods: - POST + - PUT + - path: /v3/amount** + - path: /v3/transfer** - path: /v1/deposit/manually/** - path: /v2/transfer/** - path: /transfer/** - path: /deposit/** + - path: /balanceOf** + - path: /inquiry/** + - path: /withdraw** + methods: + - POST + - PUT + - path: /otc** + methods: + - POST + - PUT + - DELETE logging: level: root: INFO