├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── dev-otc.yml │ ├── dev.yml │ ├── main-otc.yml │ ├── main.yml │ ├── pr.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── LICENSE-THIRD-PARTY ├── README.md ├── accountant ├── accountant-app │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── accountant │ │ │ │ └── app │ │ │ │ ├── AccountantApp.kt │ │ │ │ ├── config │ │ │ │ ├── AppConfig.kt │ │ │ │ ├── AppDispatchers.kt │ │ │ │ ├── ErrorHandlerConfig.kt │ │ │ │ ├── InitializeService.kt │ │ │ │ └── JsonMapperConfig.kt │ │ │ │ ├── controller │ │ │ │ ├── AccountantController.kt │ │ │ │ └── PairConfigController.kt │ │ │ │ ├── data │ │ │ │ └── PairFeeResponse.kt │ │ │ │ ├── listener │ │ │ │ ├── AccountantEventListener.kt │ │ │ │ ├── AccountantFAResponseEventListener.kt │ │ │ │ ├── AccountantTempEventListener.kt │ │ │ │ ├── AccountantTradeListener.kt │ │ │ │ ├── KycLevelUpdatedListener.kt │ │ │ │ └── OrderListener.kt │ │ │ │ ├── scheduler │ │ │ │ ├── FinancialActionsJob.kt │ │ │ │ └── TempEventsJob.kt │ │ │ │ └── utils │ │ │ │ ├── PrometheusHealthExtension.kt │ │ │ │ └── VaultUserIdMechanism.kt │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── accountant │ │ │ └── app │ │ │ ├── AccountantAppTest.kt │ │ │ ├── KafkaEnabledTest.kt │ │ │ ├── scheduler │ │ │ └── FinancialActionJobManagerIT.kt │ │ │ └── service │ │ │ └── OrderTradeManagersIT1.kt │ │ └── resources │ │ ├── application.yml │ │ └── preferences.yml ├── accountant-core │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── accountant │ │ │ └── core │ │ │ ├── api │ │ │ ├── FeeCalculator.kt │ │ │ ├── FinancialActionJobManager.kt │ │ │ ├── OrderManager.kt │ │ │ └── TradeManager.kt │ │ │ ├── inout │ │ │ ├── FinancialActionEvent.kt │ │ │ ├── KycLevelUpdatedEvent.kt │ │ │ ├── OrderStatus.kt │ │ │ ├── RichOrder.kt │ │ │ ├── RichOrderEvent.kt │ │ │ ├── RichOrderUpdate.kt │ │ │ └── RichTrade.kt │ │ │ ├── model │ │ │ ├── FeeFinancialActions.kt │ │ │ ├── FinancialAction.kt │ │ │ ├── KycLevel.kt │ │ │ ├── Order.kt │ │ │ ├── PairConfig.kt │ │ │ ├── PairFeeConfig.kt │ │ │ ├── TempEvent.kt │ │ │ └── WalletType.kt │ │ │ ├── service │ │ │ ├── FeeCalculatorImpl.kt │ │ │ ├── FinancialActionJobKafka.kt │ │ │ ├── FinancialActionJobManagerImpl.kt │ │ │ ├── OrderManagerImpl.kt │ │ │ └── TradeManagerImpl.kt │ │ │ └── spi │ │ │ ├── FinancialActionLoader.kt │ │ │ ├── FinancialActionPersister.kt │ │ │ ├── FinancialActionPublisher.kt │ │ │ ├── JsonMapper.kt │ │ │ ├── OrderPersister.kt │ │ │ ├── PairConfigLoader.kt │ │ │ ├── PairStaticRateLoader.kt │ │ │ ├── RichOrderPublisher.kt │ │ │ ├── RichTradePublisher.kt │ │ │ ├── TempEventPersister.kt │ │ │ ├── TempEventRepublisher.kt │ │ │ ├── UserLevelLoader.kt │ │ │ └── WalletProxy.kt │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── accountant │ │ └── core │ │ └── service │ │ ├── FeeCalculatorImplTest.kt │ │ ├── JsonMapperTestImpl.kt │ │ ├── OrderManagerImplTest.kt │ │ ├── TradeManagerImplTest.kt │ │ └── Valid.kt ├── accountant-ports │ ├── accountant-eventlistener-kafka │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── kotlin │ │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── accountant │ │ │ │ └── ports │ │ │ │ └── kafka │ │ │ │ └── listener │ │ │ │ ├── config │ │ │ │ └── AccountantKafkaConfig.kt │ │ │ │ ├── consumer │ │ │ │ ├── EventConsumer.kt │ │ │ │ ├── EventKafkaListener.kt │ │ │ │ ├── FAResponseKafkaListener.kt │ │ │ │ ├── KycLevelUpdatedKafkaListener.kt │ │ │ │ ├── OrderKafkaListener.kt │ │ │ │ ├── TempEventKafkaListener.kt │ │ │ │ └── TradeKafkaListener.kt │ │ │ │ ├── inout │ │ │ │ ├── FinancialActionResponseEvent.kt │ │ │ │ ├── OrderCancelRequestEvent.kt │ │ │ │ ├── OrderRequestEvent.kt │ │ │ │ └── OrderSubmitRequestEvent.kt │ │ │ │ └── spi │ │ │ │ ├── EventListener.kt │ │ │ │ ├── FAResponseListener.kt │ │ │ │ ├── KycLevelUpdatedEventListener.kt │ │ │ │ ├── Listener.kt │ │ │ │ ├── OrderSubmitRequestListener.kt │ │ │ │ ├── TempEventListener.kt │ │ │ │ └── TradeListener.kt │ │ │ └── test │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── accountant │ │ │ └── ports │ │ │ └── kafka │ │ │ └── listener │ │ │ ├── ConsumerTest.kt │ │ │ └── consumer │ │ │ ├── ConsumerObject.kt │ │ │ └── ListenerObject.kt │ ├── accountant-persister-postgres │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── kotlin │ │ │ │ └── co │ │ │ │ │ └── nilin │ │ │ │ │ └── opex │ │ │ │ │ └── accountant │ │ │ │ │ └── ports │ │ │ │ │ └── postgres │ │ │ │ │ ├── config │ │ │ │ │ └── PostgresConfig.kt │ │ │ │ │ ├── dao │ │ │ │ │ ├── FinancialActionErrorRepository.kt │ │ │ │ │ ├── FinancialActionRepository.kt │ │ │ │ │ ├── FinancialActionRetryRepository.kt │ │ │ │ │ ├── OrderRepository.kt │ │ │ │ │ ├── PairConfigRepository.kt │ │ │ │ │ ├── PairFeeConfigRepository.kt │ │ │ │ │ ├── TempEventRepository.kt │ │ │ │ │ ├── UserLevelMapperRepository.kt │ │ │ │ │ └── UserLevelRepository.kt │ │ │ │ │ ├── impl │ │ │ │ │ ├── FinancialActionLoaderImpl.kt │ │ │ │ │ ├── FinancialActionPersisterImpl.kt │ │ │ │ │ ├── OrderPersisterImpl.kt │ │ │ │ │ ├── PairConfigLoaderImpl.kt │ │ │ │ │ ├── TempEventPersisterImpl.kt │ │ │ │ │ └── UserLevelLoaderImpl.kt │ │ │ │ │ └── model │ │ │ │ │ ├── FinancialActionErrorModel.kt │ │ │ │ │ ├── FinancialActionModel.kt │ │ │ │ │ ├── FinancialActionRetryModel.kt │ │ │ │ │ ├── OrderModel.kt │ │ │ │ │ ├── PairConfigModel.kt │ │ │ │ │ ├── PairFeeConfigModel.kt │ │ │ │ │ ├── TempEventModel.kt │ │ │ │ │ ├── UserLevelMapperModel.kt │ │ │ │ │ └── UserLevelModel.kt │ │ │ └── resources │ │ │ │ └── schema.sql │ │ │ └── test │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── accountant │ │ │ └── ports │ │ │ └── postgres │ │ │ ├── FAPersisterImplTest.kt │ │ │ ├── JsonMapperTestImpl.kt │ │ │ ├── OrderPersisterImplTest.kt │ │ │ ├── PairConfigLoaderTest.kt │ │ │ ├── TempEventPersisterTest.kt │ │ │ └── Valid.kt │ ├── accountant-submitter-kafka │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── kotlin │ │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── accountant │ │ │ │ └── ports │ │ │ │ └── kafka │ │ │ │ └── submitter │ │ │ │ ├── config │ │ │ │ ├── KafkaTopicConfig.kt │ │ │ │ └── SubmitterKafkaConfig.kt │ │ │ │ └── service │ │ │ │ ├── EventPublisher.kt │ │ │ │ ├── FinancialActionSubmitter.kt │ │ │ │ ├── RichOrderSubmitter.kt │ │ │ │ ├── RichTradeSubmitter.kt │ │ │ │ └── TempEventSubmitter.kt │ │ │ └── test │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── accountant │ │ │ └── ports │ │ │ └── kafka │ │ │ └── submitter │ │ │ ├── EventPublishersTest.kt │ │ │ └── Valid.kt │ └── accountant-wallet-proxy │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── accountant │ │ │ └── ports │ │ │ └── walletproxy │ │ │ ├── config │ │ │ └── WebClientConfig.kt │ │ │ ├── data │ │ │ ├── Amount.kt │ │ │ ├── BooleanResponse.kt │ │ │ ├── Currency.kt │ │ │ └── TransferResult.kt │ │ │ └── proxy │ │ │ └── WalletProxyImpl.kt │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── accountant │ │ └── ports │ │ └── walletproxy │ │ └── proxy │ │ └── WalletProxyImplTest.kt └── pom.xml ├── api ├── api-app │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ └── main │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── api │ │ │ └── app │ │ │ ├── ApiApp.kt │ │ │ ├── config │ │ │ ├── CacheConfig.kt │ │ │ ├── InitializeService.kt │ │ │ └── SwaggerConfig.kt │ │ │ ├── controller │ │ │ └── APIKeyController.kt │ │ │ ├── data │ │ │ ├── APIKeyExpiration.kt │ │ │ ├── APIKeyResponse.kt │ │ │ ├── AccessTokenResponse.kt │ │ │ └── CreateAPIKeyRequest.kt │ │ │ ├── interceptor │ │ │ └── APIKeyFilterImpl.kt │ │ │ ├── proxy │ │ │ └── AuthProxy.kt │ │ │ ├── service │ │ │ └── APIKeyServiceImpl.kt │ │ │ └── utils │ │ │ ├── PrometheusHealthExtension.kt │ │ │ └── VaultUserIdMechanism.kt │ │ └── resources │ │ └── application.yml ├── api-core │ ├── pom.xml │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── api │ │ └── core │ │ ├── inout │ │ ├── APIKey.kt │ │ ├── AssignResponse.kt │ │ ├── AssignedAddress.kt │ │ ├── BestPrice.kt │ │ ├── CandleData.kt │ │ ├── CountResponse.kt │ │ ├── Currency.kt │ │ ├── CurrencyImplementation.kt │ │ ├── CurrencyRate.kt │ │ ├── DepositDetails.kt │ │ ├── GlobalPrice.kt │ │ ├── MarketTrade.kt │ │ ├── Order.kt │ │ ├── OrderBook.kt │ │ ├── OrderEnums.kt │ │ ├── OrderMetaData.kt │ │ ├── OrderSubmitResult.kt │ │ ├── OwnerLimitsResponse.kt │ │ ├── PairFeeResponse.kt │ │ ├── PairInfoResponse.kt │ │ ├── PriceChange.kt │ │ ├── PriceStat.kt │ │ ├── PriceTicker.kt │ │ ├── Trade.kt │ │ ├── TradeVolumeStat.kt │ │ ├── TransactionHistoryResponse.kt │ │ ├── Wallet.kt │ │ └── WithdrawHistoryResponse.kt │ │ └── spi │ │ ├── APIKeyFilter.kt │ │ ├── APIKeyService.kt │ │ ├── AccountantProxy.kt │ │ ├── BlockchainGatewayProxy.kt │ │ ├── GlobalMarketProxy.kt │ │ ├── MarketDataProxy.kt │ │ ├── MarketStatProxy.kt │ │ ├── MarketUserDataProxy.kt │ │ ├── MatchingGatewayProxy.kt │ │ ├── ProfileGatewayProxy.kt │ │ ├── SymbolMapper.kt │ │ └── WalletProxy.kt ├── api-ports │ ├── api-binance-rest │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── api │ │ │ └── ports │ │ │ └── binance │ │ │ ├── config │ │ │ ├── ErrorHandlerConfig.kt │ │ │ ├── RestConfig.kt │ │ │ ├── SecurityConfig.kt │ │ │ └── WebClientConfig.kt │ │ │ ├── controller │ │ │ ├── AccountController.kt │ │ │ ├── FiltersController.kt │ │ │ ├── LandingController.kt │ │ │ ├── MarketController.kt │ │ │ └── WalletController.kt │ │ │ ├── data │ │ │ ├── AccountInfoResponse.kt │ │ │ ├── AssetResponse.kt │ │ │ ├── AssetsEstimatedValue.kt │ │ │ ├── AssignAddressResponse.kt │ │ │ ├── BalanceResponse.kt │ │ │ ├── CancelOrderResponse.kt │ │ │ ├── CurrencyNetworkResponse.kt │ │ │ ├── DepositResponse.kt │ │ │ ├── ExchangeInfoResponse.kt │ │ │ ├── ExchangeInfoSymbol.kt │ │ │ ├── FillsData.kt │ │ │ ├── GlobalPriceResponse.kt │ │ │ ├── MarketInfoResponse.kt │ │ │ ├── MarketStatResponse.kt │ │ │ ├── NewOrderResponse.kt │ │ │ ├── OrderBookResponse.kt │ │ │ ├── PairFeeResponse.kt │ │ │ ├── QueryOrderResponse.kt │ │ │ ├── RateLimit.kt │ │ │ ├── RateLimitResponse.kt │ │ │ ├── RateLimitType.kt │ │ │ ├── RecentTradeResponse.kt │ │ │ ├── TradeResponse.kt │ │ │ ├── WithDrawRequest.kt │ │ │ └── WithdrawResponse.kt │ │ │ └── util │ │ │ ├── EnumExtensions.kt │ │ │ └── SecurityExtension.kt │ ├── api-opex-rest │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── api │ │ │ └── ports │ │ │ └── opex │ │ │ ├── config │ │ │ ├── ErrorHandlerConfig.kt │ │ │ ├── RestConfig.kt │ │ │ ├── SecurityConfig.kt │ │ │ └── WebClientConfig.kt │ │ │ ├── controller │ │ │ └── AccountController.kt │ │ │ └── util │ │ │ └── SecurityExtension.kt │ ├── api-persister-postgres │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── kotlin │ │ │ │ └── co │ │ │ │ │ └── nilin │ │ │ │ │ └── opex │ │ │ │ │ └── api │ │ │ │ │ └── ports │ │ │ │ │ └── postgres │ │ │ │ │ ├── config │ │ │ │ │ └── PostgresConfig.kt │ │ │ │ │ ├── dao │ │ │ │ │ ├── APIKeyRepository.kt │ │ │ │ │ └── SymbolMapRepository.kt │ │ │ │ │ ├── impl │ │ │ │ │ └── SymbolMapperImpl.kt │ │ │ │ │ └── model │ │ │ │ │ ├── APIKeyModel.kt │ │ │ │ │ └── SymbolMapModel.kt │ │ │ └── resources │ │ │ │ └── schema.sql │ │ │ └── test │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── api │ │ │ └── ports │ │ │ └── postgres │ │ │ └── impl │ │ │ ├── SymbolMapperTest.kt │ │ │ └── sample │ │ │ └── Samples.kt │ └── api-proxy-rest │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── api │ │ └── ports │ │ └── proxy │ │ ├── config │ │ └── ProxyDispatchers.kt │ │ ├── data │ │ ├── AllOrderRequest.kt │ │ ├── AssignAddressRequest.kt │ │ ├── CancelOrderRequest.kt │ │ ├── CreateOrderRequest.kt │ │ ├── DepositDetailsRequest.kt │ │ ├── QueryOrderRequest.kt │ │ ├── TradeRequest.kt │ │ └── TransactionRequest.kt │ │ └── impl │ │ ├── AccountantProxyImpl.kt │ │ ├── BinanceGlobalMarketProxy.kt │ │ ├── BlockchainGatewayProxyImpl.kt │ │ ├── MarketDataProxyImpl.kt │ │ ├── MarketStatProxyImpl.kt │ │ ├── MarketUserDataProxyImpl.kt │ │ ├── MatchingGatewayProxyImpl.kt │ │ └── WalletProxyImpl.kt └── pom.xml ├── bc-gateway ├── bc-gateway-app │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ └── main │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── bcgateway │ │ │ └── app │ │ │ ├── BCGatewayApp.kt │ │ │ ├── config │ │ │ ├── AppConfig.kt │ │ │ ├── AppDispatchers.kt │ │ │ ├── InitializeService.kt │ │ │ ├── SecurityConfig.kt │ │ │ ├── SwaggerConfig.kt │ │ │ └── WebClientConfig.kt │ │ │ ├── controller │ │ │ ├── AddressController.kt │ │ │ ├── AdminController.kt │ │ │ ├── CurrencyController.kt │ │ │ ├── DepositController.kt │ │ │ └── WalletSyncController.kt │ │ │ ├── dto │ │ │ ├── AddChainRequest.kt │ │ │ ├── AddCurrencyRequest.kt │ │ │ ├── AddressTypeRequest.kt │ │ │ ├── ChainEndpointRequest.kt │ │ │ ├── ChainResponse.kt │ │ │ ├── TokenRequest.kt │ │ │ └── TokenResponse.kt │ │ │ ├── listener │ │ │ └── AdminEventListenerImpl.kt │ │ │ ├── service │ │ │ ├── AddressAllocatorJob.kt │ │ │ └── AdminService.kt │ │ │ └── utils │ │ │ ├── Extensions.kt │ │ │ ├── PrometheusHealthExtension.kt │ │ │ └── VaultUserIdMechanism.kt │ │ └── resources │ │ ├── application-otc.yml │ │ └── application.yml ├── bc-gateway-core │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── bcgateway │ │ │ │ └── core │ │ │ │ ├── api │ │ │ │ ├── AssignAddressService.kt │ │ │ │ ├── DepositService.kt │ │ │ │ ├── InfoService.kt │ │ │ │ └── WalletSyncService.kt │ │ │ │ ├── model │ │ │ │ ├── AddressStatus.kt │ │ │ │ ├── AddressType.kt │ │ │ │ ├── AssignedAddress.kt │ │ │ │ ├── Chain.kt │ │ │ │ ├── Currency.kt │ │ │ │ ├── CurrencyImplementation.kt │ │ │ │ ├── CurrencyInfo.kt │ │ │ │ ├── Deposit.kt │ │ │ │ ├── ReservedAddress.kt │ │ │ │ ├── Transfer.kt │ │ │ │ ├── Wallet.kt │ │ │ │ ├── WithdrawData.kt │ │ │ │ └── otc │ │ │ │ │ ├── LoginRequest.kt │ │ │ │ │ └── LoginResponse.kt │ │ │ │ ├── service │ │ │ │ ├── AssignAddressServiceImpl.kt │ │ │ │ ├── DepositService.kt │ │ │ │ ├── InfoServiceImpl.kt │ │ │ │ └── WalletSyncServiceImpl.kt │ │ │ │ ├── spi │ │ │ │ ├── AddressManager.kt │ │ │ │ ├── AddressTypeHandler.kt │ │ │ │ ├── AssignedAddressHandler.kt │ │ │ │ ├── AuthProxy.kt │ │ │ │ ├── ChainLoader.kt │ │ │ │ ├── CurrencyHandler.kt │ │ │ │ ├── DepositHandler.kt │ │ │ │ ├── ReservedAddressHandler.kt │ │ │ │ └── WalletProxy.kt │ │ │ │ └── utils │ │ │ │ └── LoggerDelegate.kt │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── bcgateway │ │ └── core │ │ └── service │ │ └── AssignAddressServiceImplUnitTest.kt ├── bc-gateway-ports │ ├── bc-gateway-auth-proxy │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── bcgateway │ │ │ └── ports │ │ │ └── authproxy │ │ │ └── impl │ │ │ └── AuthProxyImpl.kt │ ├── bc-gateway-eventlistener-kafka │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── bcgateway │ │ │ └── ports │ │ │ └── kafka │ │ │ └── listener │ │ │ ├── config │ │ │ ├── KafkaConfig.kt │ │ │ └── KafkaProducerConfig.kt │ │ │ ├── consumer │ │ │ └── AdminEventKafkaListener.kt │ │ │ ├── model │ │ │ ├── AddCurrencyEvent.kt │ │ │ ├── AdminEvent.kt │ │ │ ├── DeleteCurrencyEvent.kt │ │ │ └── EditCurrencyEvent.kt │ │ │ └── spi │ │ │ └── AdminEventListener.kt │ ├── bc-gateway-persister-postgres │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── kotlin │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── bcgateway │ │ │ │ └── ports │ │ │ │ └── postgres │ │ │ │ ├── config │ │ │ │ └── PostgresConfig.kt │ │ │ │ ├── dao │ │ │ │ ├── AddressTypeRepository.kt │ │ │ │ ├── AssignedAddressChainRepository.kt │ │ │ │ ├── AssignedAddressRepository.kt │ │ │ │ ├── ChainAddressTypeRepository.kt │ │ │ │ ├── ChainRepository.kt │ │ │ │ ├── CurrencyImplementationRepository.kt │ │ │ │ ├── CurrencyRepository.kt │ │ │ │ ├── DepositRepository.kt │ │ │ │ └── ReservedAddressRepository.kt │ │ │ │ ├── impl │ │ │ │ ├── AddressManagerImpl.kt │ │ │ │ ├── AddressTypeHandlerImpl.kt │ │ │ │ ├── AssignedAddressHandlerImpl.kt │ │ │ │ ├── ChainHandler.kt │ │ │ │ ├── CurrencyHandlerImpl.kt │ │ │ │ ├── DepositHandlerImpl.kt │ │ │ │ └── ReservedAddressHandlerImpl.kt │ │ │ │ └── model │ │ │ │ ├── AddressTypeModel.kt │ │ │ │ ├── AssignedAddressChainModel.kt │ │ │ │ ├── AssignedAddressModel.kt │ │ │ │ ├── ChainAddressTypeModel.kt │ │ │ │ ├── ChainModel.kt │ │ │ │ ├── CurrencyImplementationModel.kt │ │ │ │ ├── CurrencyModel.kt │ │ │ │ ├── DepositModel.kt │ │ │ │ └── ReservedAddressModel.kt │ │ │ └── resources │ │ │ └── schema.sql │ └── bc-gateway-wallet-proxy │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── bcgateway │ │ └── ports │ │ └── walletproxy │ │ ├── impl │ │ ├── ExtractBackgroundAuth.kt │ │ └── WalletProxyImpl.kt │ │ └── model │ │ ├── Amount.kt │ │ ├── Currency.kt │ │ └── TransferResult.kt └── pom.xml ├── common ├── pom.xml └── src │ └── main │ └── kotlin │ └── co │ └── nilin │ └── opex │ └── common │ ├── CommonErrorConfig.kt │ ├── OpexError.kt │ └── utils │ ├── DynamicInterval.kt │ ├── Extensions.kt │ ├── Interval.kt │ └── LoggerDelegate.kt ├── docker-compose-otc.build.yml ├── docker-compose-otc.local.yml ├── docker-compose-otc.override.yml ├── docker-compose-otc.yml ├── docker-compose.build.yml ├── docker-compose.local.yml ├── docker-compose.override.yml ├── docker-compose.yml ├── docker-images ├── kafka │ ├── Dockerfile │ ├── jmx-exporter-0.16.1.jar │ └── kafka-jmx-exporter.yml ├── postgres │ ├── Dockerfile │ └── add-backup-user.sh └── vault │ ├── Dockerfile │ ├── backend-policy.hcl │ ├── panel-policy.hcl │ ├── vault.json │ └── workflow-vault.sh ├── eventlog ├── eventlog-app │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ └── main │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ ├── eventlog │ │ │ └── app │ │ │ │ ├── EventLogApp.kt │ │ │ │ ├── config │ │ │ │ └── AppConfig.kt │ │ │ │ ├── listeners │ │ │ │ ├── DeadLetterListener.kt │ │ │ │ ├── EventlogEventListener.kt │ │ │ │ ├── EventlogTradeListener.kt │ │ │ │ └── OrderListener.kt │ │ │ │ └── utils │ │ │ │ └── PrometheusHealthExtension.kt │ │ │ └── util │ │ │ └── vault │ │ │ └── VaultUserIdMechanism.kt │ │ └── resources │ │ └── application.yml ├── eventlog-core │ ├── pom.xml │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── eventlog │ │ └── core │ │ ├── inout │ │ ├── DeadLetterEvent.kt │ │ └── OriginModule.kt │ │ └── spi │ │ ├── DeadLetter.kt │ │ ├── DeadLetterPersister.kt │ │ ├── Event.kt │ │ ├── EventPersister.kt │ │ ├── Order.kt │ │ ├── OrderPersister.kt │ │ ├── Trade.kt │ │ └── TradePersister.kt ├── eventlog-ports │ ├── eventlog-eventlistener-kafka │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── eventlog │ │ │ └── ports │ │ │ └── kafka │ │ │ └── listener │ │ │ ├── config │ │ │ ├── EventLogKafkaConfig.kt │ │ │ ├── KafkaProducerConfig.kt │ │ │ └── KafkaTopicConfig.kt │ │ │ ├── consumer │ │ │ ├── DLTKafkaListener.kt │ │ │ ├── EventKafkaListener.kt │ │ │ ├── OrderKafkaListener.kt │ │ │ └── TradeKafkaListener.kt │ │ │ ├── inout │ │ │ ├── OrderCancelRequestEvent.kt │ │ │ ├── OrderRequestEvent.kt │ │ │ └── OrderSubmitRequestEvent.kt │ │ │ └── spi │ │ │ ├── DLTListener.kt │ │ │ ├── EventListener.kt │ │ │ ├── OrderSubmitRequestListener.kt │ │ │ └── TradeListener.kt │ └── eventlog-persister-postgres │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── eventlog │ │ │ └── ports │ │ │ └── postgres │ │ │ ├── config │ │ │ └── PostgresConfig.kt │ │ │ ├── dao │ │ │ ├── DeadLetterEventRepository.kt │ │ │ ├── EventRepository.kt │ │ │ ├── OrderEventRepository.kt │ │ │ ├── OrderRepository.kt │ │ │ └── TradeRepository.kt │ │ │ ├── impl │ │ │ ├── DeadLetterPersisterImpl.kt │ │ │ ├── EventPersisterImpl.kt │ │ │ ├── OrderPersisterImpl.kt │ │ │ └── TradePersisterImpl.kt │ │ │ └── model │ │ │ ├── DeadLetterEventModel.kt │ │ │ ├── EventModel.kt │ │ │ ├── OrderEventsModel.kt │ │ │ ├── OrderModel.kt │ │ │ └── TradeModel.kt │ │ └── resources │ │ └── schema.sql └── pom.xml ├── market ├── market-app │ ├── .gitignore │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ └── main │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── market │ │ │ └── app │ │ │ ├── MarketAppApplication.kt │ │ │ ├── config │ │ │ ├── AppConfig.kt │ │ │ ├── AppDispatchers.kt │ │ │ ├── CacheConfig.kt │ │ │ ├── InitializeService.kt │ │ │ ├── SecurityConfig.kt │ │ │ └── WebClientConfig.kt │ │ │ ├── controller │ │ │ ├── ChartController.kt │ │ │ ├── MarketController.kt │ │ │ ├── MarketStatsController.kt │ │ │ ├── OrderController.kt │ │ │ ├── RateController.kt │ │ │ └── UserDataController.kt │ │ │ ├── data │ │ │ └── CountResponse.kt │ │ │ ├── listener │ │ │ └── MarketListenerImpl.kt │ │ │ ├── service │ │ │ └── ReportingService.kt │ │ │ └── utils │ │ │ ├── Extensions.kt │ │ │ ├── PrometheusHealthExtension.kt │ │ │ └── VaultUserIdMechanism.kt │ │ └── resources │ │ └── application.yml ├── market-core │ ├── pom.xml │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── market │ │ └── core │ │ ├── event │ │ ├── RichOrder.kt │ │ ├── RichOrderEvent.kt │ │ ├── RichOrderUpdate.kt │ │ └── RichTrade.kt │ │ ├── inout │ │ ├── AggregatedOrderPriceModel.kt │ │ ├── AllOrderRequest.kt │ │ ├── BestPrice.kt │ │ ├── CandleData.kt │ │ ├── CurrencyRate.kt │ │ ├── MarketTrade.kt │ │ ├── Order.kt │ │ ├── OrderBook.kt │ │ ├── OrderEnums.kt │ │ ├── OrderMetaData.kt │ │ ├── PriceChange.kt │ │ ├── PriceStat.kt │ │ ├── PriceTicker.kt │ │ ├── QueryOrderRequest.kt │ │ ├── RateSource.kt │ │ ├── Trade.kt │ │ ├── TradeRequest.kt │ │ ├── TradeVolumeStat.kt │ │ ├── Transaction.kt │ │ ├── TransactionRequest.kt │ │ └── TransactionResponse.kt │ │ └── spi │ │ ├── MarketQueryHandler.kt │ │ ├── MarketRateService.kt │ │ ├── OrderPersister.kt │ │ ├── TradePersister.kt │ │ └── UserQueryHandler.kt ├── market-ports │ ├── market-eventlistener-kafka │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── market │ │ │ └── ports │ │ │ └── kafka │ │ │ └── listener │ │ │ ├── config │ │ │ ├── KafkaConsumerConfig.kt │ │ │ ├── KafkaProducerConfig.kt │ │ │ └── KafkaTopicConfig.kt │ │ │ ├── consumer │ │ │ ├── OrderKafkaListener.kt │ │ │ └── TradeKafkaListener.kt │ │ │ └── spi │ │ │ ├── RichOrderListener.kt │ │ │ └── RichTradeListener.kt │ └── market-persister-postgres │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── market │ │ │ │ └── ports │ │ │ │ └── postgres │ │ │ │ ├── config │ │ │ │ └── PostgresConfig.kt │ │ │ │ ├── dao │ │ │ │ ├── CurrencyRateRepository.kt │ │ │ │ ├── OpenOrderRepository.kt │ │ │ │ ├── OrderRepository.kt │ │ │ │ ├── OrderStatusRepository.kt │ │ │ │ └── TradeRepository.kt │ │ │ │ ├── impl │ │ │ │ ├── MarketQueryHandlerImpl.kt │ │ │ │ ├── MarketRateServiceImpl.kt │ │ │ │ ├── OrderPersisterImpl.kt │ │ │ │ ├── TradePersisterImpl.kt │ │ │ │ └── UserQueryHandlerImpl.kt │ │ │ │ ├── model │ │ │ │ ├── CandleInfoData.kt │ │ │ │ ├── CurrencyRateModel.kt │ │ │ │ ├── LastPrice.kt │ │ │ │ ├── OpenOrderModel.kt │ │ │ │ ├── OrderModel.kt │ │ │ │ ├── OrderStatusModel.kt │ │ │ │ ├── TradeModel.kt │ │ │ │ └── TradeTickerData.kt │ │ │ │ └── util │ │ │ │ ├── CacheHelper.kt │ │ │ │ ├── CacheValueWrapper.java │ │ │ │ ├── Convertor.kt │ │ │ │ ├── DTOExtensions.kt │ │ │ │ ├── EnumExtensions.kt │ │ │ │ └── RedisCacheHelper.kt │ │ └── resources │ │ │ └── schema.sql │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── market │ │ └── ports │ │ └── postgres │ │ └── impl │ │ ├── MarketQueryHandlerTest.kt │ │ ├── OrderPersisterTest.kt │ │ ├── TradePersisterTest.kt │ │ ├── UserQueryHandlerTest.kt │ │ └── sample │ │ └── Samples.kt └── pom.xml ├── matching-engine ├── matching-engine-app │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── matching │ │ │ │ └── engine │ │ │ │ └── app │ │ │ │ ├── MatchingEngineApp.kt │ │ │ │ ├── bl │ │ │ │ ├── ExchangeEventHandler.kt │ │ │ │ └── OrderBooks.kt │ │ │ │ ├── config │ │ │ │ ├── AppConfig.kt │ │ │ │ ├── AppSchedulers.kt │ │ │ │ └── InitializeService.kt │ │ │ │ ├── listener │ │ │ │ ├── MatchingEngineEventListener.kt │ │ │ │ └── OrderListener.kt │ │ │ │ └── utils │ │ │ │ └── PrometheusHealthExtension.kt │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── matching │ │ └── engine │ │ └── app │ │ └── OrderBookEventEmitsUnitTest.kt ├── matching-engine-core │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── matching │ │ │ └── engine │ │ │ └── core │ │ │ ├── engine │ │ │ └── SimpleOrderBook.kt │ │ │ ├── eventh │ │ │ ├── EventDispatcher.kt │ │ │ └── events │ │ │ │ ├── CancelOrderEvent.kt │ │ │ │ ├── CoreEvent.kt │ │ │ │ ├── CreateOrderEvent.kt │ │ │ │ ├── EditOrderRequestEvent.kt │ │ │ │ ├── OneOrderEvent.kt │ │ │ │ ├── OrderBookPublishedEvent.kt │ │ │ │ ├── RejectOrderEvent.kt │ │ │ │ ├── SubmitOrderEvent.kt │ │ │ │ ├── TradeEvent.kt │ │ │ │ └── UpdatedOrderEvent.kt │ │ │ ├── factory │ │ │ └── OrderBookFactory.kt │ │ │ ├── inout │ │ │ ├── OrderCancelCommand.kt │ │ │ ├── OrderCancelRequestEvent.kt │ │ │ ├── OrderCreateCommand.kt │ │ │ ├── OrderEditCommand.kt │ │ │ ├── OrderRequestEvent.kt │ │ │ ├── OrderSubmitRequestEvent.kt │ │ │ ├── RejectReason.kt │ │ │ └── RequestedOperation.kt │ │ │ ├── model │ │ │ ├── Bucket.kt │ │ │ ├── Order.kt │ │ │ ├── OrderBook.kt │ │ │ ├── OrderMetaData.kt │ │ │ ├── Pair.kt │ │ │ ├── PersistentOrder.kt │ │ │ ├── PersistentOrderBook.kt │ │ │ └── SimpleOrder.kt │ │ │ └── spi │ │ │ └── OrderBookPersister.kt │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── matching │ │ └── engine │ │ └── core │ │ └── SimpleOrderBookUnitTest.kt ├── matching-engine-ports │ ├── matching-engine-eventlistener-kafka │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── matching │ │ │ └── engine │ │ │ └── ports │ │ │ └── kafka │ │ │ └── listener │ │ │ ├── config │ │ │ └── OrderKafkaConfig.kt │ │ │ ├── consumer │ │ │ ├── EventKafkaListener.kt │ │ │ └── OrderKafkaListener.kt │ │ │ └── spi │ │ │ ├── EventListener.kt │ │ │ └── OrderRequestEventListener.kt │ ├── matching-engine-snapshots-redis │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── matching │ │ │ └── engine │ │ │ └── ports │ │ │ └── redis │ │ │ ├── config │ │ │ └── RedisConfig.kt │ │ │ └── service │ │ │ └── OrderBookPersister.kt │ └── matching-engine-submitter-kafka │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── matching │ │ └── engine │ │ └── ports │ │ └── kafka │ │ └── submitter │ │ ├── config │ │ ├── EventsKafkaConfig.kt │ │ ├── KafkaAdminConfig.kt │ │ └── KafkaTopicConfig.kt │ │ └── service │ │ └── EventsSubmitter.kt └── pom.xml ├── matching-gateway ├── matching-gateway-app │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── matching │ │ │ │ └── gateway │ │ │ │ └── app │ │ │ │ ├── MatchingGatewayApp.kt │ │ │ │ ├── config │ │ │ │ ├── AppConfig.kt │ │ │ │ ├── SecurityConfig.kt │ │ │ │ ├── SwaggerConfig.kt │ │ │ │ └── WebClientConfig.kt │ │ │ │ ├── controller │ │ │ │ ├── ControllerExceptionHandler.kt │ │ │ │ └── OrderController.kt │ │ │ │ ├── exception │ │ │ │ └── NotAllowedToSubmitOrderException.kt │ │ │ │ ├── inout │ │ │ │ ├── BooleanResponse.kt │ │ │ │ ├── CancelOrderRequest.kt │ │ │ │ ├── CreateOrderRequest.kt │ │ │ │ ├── PairConfig.kt │ │ │ │ └── PairFeeConfig.kt │ │ │ │ ├── proxy │ │ │ │ ├── AccountantProxyImpl.kt │ │ │ │ └── PairConfigLoaderImpl.kt │ │ │ │ ├── service │ │ │ │ └── OrderService.kt │ │ │ │ ├── spi │ │ │ │ ├── AccountantApiProxy.kt │ │ │ │ └── PairConfigLoader.kt │ │ │ │ └── utils │ │ │ │ └── PrometheusHealthExtension.kt │ │ └── resources │ │ │ └── application.yml │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── matching │ │ └── gateway │ │ └── app │ │ └── service │ │ ├── OrderServiceTest.kt │ │ └── sample │ │ └── Samples.kt ├── matching-gateway-port │ └── matching-gateway-submitter-kafka │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── matching │ │ └── gateway │ │ └── ports │ │ └── kafka │ │ └── submitter │ │ ├── config │ │ ├── KafkaAdminConfig.kt │ │ └── OrderKafkaConfig.kt │ │ ├── inout │ │ ├── OrderCancelRequestEvent.kt │ │ ├── OrderRequestEvent.kt │ │ ├── OrderSubmitRequestEvent.kt │ │ └── OrderSubmitResult.kt │ │ └── service │ │ ├── EventSubmitter.kt │ │ ├── KafkaHealthIndicator.kt │ │ └── OrderRequestEventSubmitter.kt └── pom.xml ├── pom.xml ├── preferences-demo.yml ├── preferences-dev.yml ├── user-management ├── keycloak-gateway │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ └── main │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── auth │ │ │ └── gateway │ │ │ ├── ApplicationContextHolder.kt │ │ │ ├── KeycloakGatewayApp.kt │ │ │ ├── authenticator │ │ │ ├── CustomOTPAuthenticator.kt │ │ │ └── UserNotesAuthenticator.kt │ │ │ ├── config │ │ │ ├── AppConfig.kt │ │ │ ├── EmbeddedKeycloakApplication.kt │ │ │ ├── EmbeddedKeycloakConfig.kt │ │ │ ├── EmbeddedKeycloakRequestFilter.kt │ │ │ ├── KafkaConfig.kt │ │ │ ├── KeycloakServerProperties.kt │ │ │ ├── RegularJsonConfigProviderFactory.kt │ │ │ ├── Resteasy3Provider.kt │ │ │ ├── SimplePlatformProvider.kt │ │ │ └── SystemPropertyConfig.kt │ │ │ ├── data │ │ │ ├── ChangePasswordRequest.kt │ │ │ ├── ForgotPasswordRequest.kt │ │ │ ├── Get2FAResponse.kt │ │ │ ├── KYCStatus.kt │ │ │ ├── KYCStatusResponse.kt │ │ │ ├── KycRequest.kt │ │ │ ├── RegisterUserRequest.kt │ │ │ ├── RegisterUserResponse.kt │ │ │ ├── Setup2FARequest.kt │ │ │ ├── UploadResponse.kt │ │ │ ├── UserProfileInfo.kt │ │ │ ├── UserSecurityCheckResponse.kt │ │ │ ├── UserSessionResponse.kt │ │ │ ├── WhiteListAdaptor.kt │ │ │ └── Whitelist.kt │ │ │ ├── extension │ │ │ ├── ExtendedEventListenerProvider.kt │ │ │ ├── ExtendedEventListenerProviderFactory.kt │ │ │ ├── HashicorpVaultProvider.java │ │ │ ├── HashicorpVaultProviderFactory.java │ │ │ ├── RegistrationOpexCaptcha.kt │ │ │ ├── UserManagementResource.kt │ │ │ ├── UserManagementResourceFactory.kt │ │ │ ├── UserProfileResource.kt │ │ │ ├── UserProfileResourceFactory.kt │ │ │ └── VaultService.java │ │ │ ├── listener │ │ │ └── KycLevelUpdatedListener.kt │ │ │ ├── model │ │ │ ├── ActionTokenResult.kt │ │ │ ├── AuthEvent.kt │ │ │ ├── UserCreatedEvent.kt │ │ │ └── WhiteListModel.kt │ │ │ ├── providers │ │ │ ├── CustomEmailTemplateProvider.kt │ │ │ ├── CustomEmailTemplateProviderFactory.kt │ │ │ ├── CustomJpaEntityProviderFactory.kt │ │ │ ├── CustomJpaProvider.kt │ │ │ └── CustomOIDCProtocolMapper.kt │ │ │ └── utils │ │ │ ├── ActionTokenHelper.kt │ │ │ ├── ErrorHandler.kt │ │ │ ├── Extensions.kt │ │ │ ├── OTPUtils.kt │ │ │ ├── PrometheusHealthExtension.kt │ │ │ ├── ResourceAuthenticator.kt │ │ │ └── VaultUserIdMechanism.kt │ │ └── resources │ │ ├── META-INF │ │ ├── keycloak-server.json │ │ ├── services │ │ │ ├── org.keycloak.authentication.AuthenticatorFactory │ │ │ ├── org.keycloak.authentication.FormActionFactory │ │ │ ├── org.keycloak.common.util.ResteasyProvider │ │ │ ├── org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory │ │ │ ├── org.keycloak.email.EmailTemplateProviderFactory │ │ │ ├── org.keycloak.events.EventListenerProviderFactory │ │ │ ├── org.keycloak.platform.PlatformProvider │ │ │ ├── org.keycloak.protocol.ProtocolMapper │ │ │ ├── org.keycloak.services.resource.RealmResourceProviderFactory │ │ │ └── org.keycloak.vault.VaultProviderFactory │ │ └── whitelisttt-changelog.xml │ │ ├── application.yml │ │ ├── email-templates │ │ ├── execute-action.html │ │ ├── password-reset.html │ │ ├── test-smtp.html │ │ └── verify-email.html │ │ ├── opex-master-realm.json │ │ └── opex-realm.json ├── pom.xml ├── user-management-core │ ├── .gitignore │ ├── pom.xml │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── auth │ │ └── core │ │ ├── data │ │ ├── KycLevel.kt │ │ └── KycLevelUpdatedEvent.kt │ │ └── spi │ │ └── KycLevelUpdatedEventListener.kt └── user-management-ports │ └── user-management-kafka-listener │ ├── .gitignore │ ├── pom.xml │ └── src │ ├── main │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── user.managment │ │ │ └── ports │ │ │ └── kafka │ │ │ ├── config │ │ │ └── KafkaListenerConfig.kt │ │ │ └── consumer │ │ │ └── KycLevelUpdatedKafkaListener.kt │ └── resources │ │ └── application.properties │ └── test │ └── kotlin │ └── co │ └── nilin │ └── opex │ └── profile │ └── ports │ └── kafka │ └── ProfilePostgressApplicationTests.kt ├── wallet ├── pom.xml ├── wallet-app │ ├── Dockerfile │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── co │ │ │ │ └── nilin │ │ │ │ └── opex │ │ │ │ └── wallet │ │ │ │ └── app │ │ │ │ ├── WalletApp.kt │ │ │ │ ├── config │ │ │ │ ├── AppConfig.kt │ │ │ │ ├── AppDispatchers.kt │ │ │ │ ├── CurrencyRatesConfig.kt │ │ │ │ ├── InitializeService.kt │ │ │ │ ├── ObjectMapperConfig.kt │ │ │ │ ├── RestConfig.kt │ │ │ │ ├── SecurityConfig.kt │ │ │ │ ├── SwaggerConfig.kt │ │ │ │ └── WebClientConfig.kt │ │ │ │ ├── controller │ │ │ │ ├── AdvancedTransferController.kt │ │ │ │ ├── BalanceController.kt │ │ │ │ ├── CurrencyRatesController.kt │ │ │ │ ├── DepositController.kt │ │ │ │ ├── InquiryController.kt │ │ │ │ ├── LegacyTransactionController.kt │ │ │ │ ├── PaymentGatewayController.kt │ │ │ │ ├── TransactionController.kt │ │ │ │ ├── TransferController.kt │ │ │ │ ├── WalletOwnerController.kt │ │ │ │ ├── WalletStatController.kt │ │ │ │ ├── WithdrawAdminController.kt │ │ │ │ └── WithdrawController.kt │ │ │ │ ├── dto │ │ │ │ ├── AddCurrencyRequest.kt │ │ │ │ ├── AdminSearchWithdrawRequest.kt │ │ │ │ ├── AdvanceReservedTransferData.kt │ │ │ │ ├── CurrencyExchangeRatesResponse.kt │ │ │ │ ├── CurrencyPair.kt │ │ │ │ ├── DepositHistoryRequest.kt │ │ │ │ ├── DepositResponse.kt │ │ │ │ ├── ManualTransferRequest.kt │ │ │ │ ├── OwnerLimitsResponse.kt │ │ │ │ ├── PaymentCurrency.kt │ │ │ │ ├── PaymentDepositRequest.kt │ │ │ │ ├── PaymentDepositResponse.kt │ │ │ │ ├── RequestWithdrawBody.kt │ │ │ │ ├── ReservedTransferResponse.kt │ │ │ │ ├── SearchWithdrawRequest.kt │ │ │ │ ├── SetCurrencyExchangeRateRequest.kt │ │ │ │ ├── TransactionRequest.kt │ │ │ │ ├── TransferPreEvaluateResponse.kt │ │ │ │ ├── TransferRequest.kt │ │ │ │ ├── TransferReserveRequest.kt │ │ │ │ ├── TransferReserveResponse.kt │ │ │ │ ├── UserTransactionRequest.kt │ │ │ │ ├── WalletData.kt │ │ │ │ └── WithdrawHistoryRequest.kt │ │ │ │ ├── listener │ │ │ │ ├── AdminEventListenerImpl.kt │ │ │ │ ├── FinancialActionEventListenerImpl.kt │ │ │ │ ├── WalletListenerImpl.kt │ │ │ │ └── WalletUserCreatedEventListener.kt │ │ │ │ ├── service │ │ │ │ ├── BackupService.kt │ │ │ │ ├── TransferService.kt │ │ │ │ ├── UserRegistrationService.kt │ │ │ │ └── otc │ │ │ │ │ ├── CurrencyService.kt │ │ │ │ │ ├── GraphService.kt │ │ │ │ │ └── OTCCurrencyService.kt │ │ │ │ └── utils │ │ │ │ ├── BalanceParser.kt │ │ │ │ ├── Extensions.kt │ │ │ │ ├── PrometheusHealthExtension.kt │ │ │ │ └── VaultUserIdMechanism.kt │ │ └── resources │ │ │ ├── application-otc.yml │ │ │ └── application.yml │ │ └── test │ │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── wallet │ │ │ └── app │ │ │ ├── KafkaEnabledTest.kt │ │ │ ├── TestProfileSecurityConfig.kt │ │ │ ├── WalletAppTest.kt │ │ │ ├── controller │ │ │ ├── AdvancedTransferControllerIT.kt │ │ │ ├── CurrencyRatesControllerIT.kt │ │ │ ├── TransactionControllerIT.kt │ │ │ └── TransferControllerIT.kt │ │ │ └── service │ │ │ ├── TransactionManagerImplIT.kt │ │ │ ├── TransferManagerImplIT.kt │ │ │ └── otc │ │ │ └── CurrencyGraphIT.kt │ │ └── resources │ │ └── application.yml ├── wallet-core │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── wallet │ │ │ └── core │ │ │ ├── exc │ │ │ ├── ConcurrentBalanceChangException.kt │ │ │ ├── CurrencyNotMatchedException.kt │ │ │ ├── DepositLimitExceededException.kt │ │ │ ├── NotEnoughBalanceException.kt │ │ │ └── WithdrawLimitExceededException.kt │ │ │ ├── inout │ │ │ ├── Deposit.kt │ │ │ ├── FinancialActionResponseEvent.kt │ │ │ ├── TransferCommand.kt │ │ │ ├── TransferResult.kt │ │ │ ├── WalletData.kt │ │ │ ├── WalletTotal.kt │ │ │ ├── WithdrawAcceptCommand.kt │ │ │ ├── WithdrawActionResult.kt │ │ │ ├── WithdrawCommand.kt │ │ │ ├── WithdrawData.kt │ │ │ ├── WithdrawRejectCommand.kt │ │ │ └── WithdrawResponse.kt │ │ │ ├── model │ │ │ ├── Amount.kt │ │ │ ├── BriefWallet.kt │ │ │ ├── Currency.kt │ │ │ ├── DepositStatus.kt │ │ │ ├── DepositType.kt │ │ │ ├── TokenHolder.kt │ │ │ ├── Transaction.kt │ │ │ ├── TransactionHistory.kt │ │ │ ├── TransactionWithDetailHistory.kt │ │ │ ├── TransferCategory.kt │ │ │ ├── UserTransaction.kt │ │ │ ├── UserTransactionCategory.kt │ │ │ ├── UserTransactionHistory.kt │ │ │ ├── Wallet.kt │ │ │ ├── WalletLimitAction.kt │ │ │ ├── WalletOwner.kt │ │ │ ├── WalletType.kt │ │ │ ├── Withdraw.kt │ │ │ ├── WithdrawStatus.kt │ │ │ └── otc │ │ │ │ ├── CurrencyImplementationResponse.kt │ │ │ │ ├── ForbiddenPair.kt │ │ │ │ ├── LoginRequest.kt │ │ │ │ ├── LoginResponse.kt │ │ │ │ ├── Rate.kt │ │ │ │ ├── ReservedTransfer.kt │ │ │ │ └── Symbols.kt │ │ │ ├── service │ │ │ ├── TransferManagerImpl.kt │ │ │ ├── WithdrawService.kt │ │ │ └── otc │ │ │ │ ├── CurrencyGraph.kt │ │ │ │ └── RateService.kt │ │ │ └── spi │ │ │ ├── AuthProxy.kt │ │ │ ├── BcGatewayProxy.kt │ │ │ ├── CurrencyRateService.kt │ │ │ ├── CurrencyService.kt │ │ │ ├── DepositPersister.kt │ │ │ ├── FiActionResponseEventSubmitter.kt │ │ │ ├── ReservedTransferManager.kt │ │ │ ├── TransactionManager.kt │ │ │ ├── TransferManager.kt │ │ │ ├── UserTransactionManager.kt │ │ │ ├── WalletDataManager.kt │ │ │ ├── WalletListener.kt │ │ │ ├── WalletManager.kt │ │ │ ├── WalletOwnerManager.kt │ │ │ └── WithdrawPersister.kt │ │ └── test │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── wallet │ │ └── core │ │ └── service │ │ ├── TransferManagerImplTest.kt │ │ └── sample │ │ └── Samples.kt └── wallet-ports │ ├── wallet-auth-proxy │ ├── pom.xml │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── wallet │ │ └── ports │ │ └── proxy │ │ └── auth │ │ └── impl │ │ └── AuthProxyImpl.kt │ ├── wallet-bcgateway-proxy │ ├── pom.xml │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── wallet │ │ └── ports │ │ └── proxy │ │ └── bcgateway │ │ └── impl │ │ ├── BcGatewayProxyImpl.kt │ │ └── ExtractBackgroundAuth.kt │ ├── wallet-eventlistener-kafka │ ├── pom.xml │ └── src │ │ └── main │ │ └── kotlin │ │ └── co │ │ └── nilin │ │ └── opex │ │ └── wallet │ │ └── ports │ │ └── kafka │ │ └── listener │ │ ├── config │ │ ├── KafkaProducerConfig.kt │ │ ├── KafkaTopicConfig.kt │ │ └── WalletKafkaConfig.kt │ │ ├── consumer │ │ ├── AdminEventKafkaListener.kt │ │ ├── FinancialActionKafkaListener.kt │ │ └── UserCreatedKafkaListener.kt │ │ ├── model │ │ ├── AddCurrencyEvent.kt │ │ ├── AdminEvent.kt │ │ ├── AuthEvent.kt │ │ ├── DeleteCurrencyEvent.kt │ │ ├── EditCurrencyEvent.kt │ │ ├── FinancialActionEvent.kt │ │ └── UserCreatedEvent.kt │ │ ├── spi │ │ ├── AdminEventListener.kt │ │ ├── FinancialActionEventListener.kt │ │ └── UserCreatedEventListener.kt │ │ └── submitter │ │ └── FIActionResponseSubmitter.kt │ └── wallet-persister-postgres │ ├── pom.xml │ └── src │ ├── main │ ├── kotlin │ │ └── co │ │ │ └── nilin │ │ │ └── opex │ │ │ └── wallet │ │ │ └── ports │ │ │ └── postgres │ │ │ ├── config │ │ │ └── PostgresConfig.kt │ │ │ ├── dao │ │ │ ├── CurrencyRepository.kt │ │ │ ├── DepositRepository.kt │ │ │ ├── ForbiddenPairRepository.kt │ │ │ ├── RatesRepository.kt │ │ │ ├── ReservedTransferRepository.kt │ │ │ ├── TransactionRepository.kt │ │ │ ├── UserTransactionRepository.kt │ │ │ ├── WalletConfigRepository.kt │ │ │ ├── WalletLimitsRepository.kt │ │ │ ├── WalletOwnerRepository.kt │ │ │ ├── WalletRepository.kt │ │ │ └── WithdrawRepository.kt │ │ │ ├── dto │ │ │ ├── CurrencyDto.kt │ │ │ ├── DepositWithdrawTransaction.kt │ │ │ ├── TransactionStat.kt │ │ │ ├── TransactionWithDetail.kt │ │ │ ├── WalletDto.kt │ │ │ ├── WalletOwnerDto.kt │ │ │ └── WalletStatExclusion.kt │ │ │ ├── impl │ │ │ ├── CurrencyServiceImpl.kt │ │ │ ├── DepositPersisterImpl.kt │ │ │ ├── RateServiceImpl.kt │ │ │ ├── ReservedTransferImpl.kt │ │ │ ├── TransactionManagerImpl.kt │ │ │ ├── UserTransactionManagerImpl.kt │ │ │ ├── WalletDataManagerImpl.kt │ │ │ ├── WalletManagerImpl.kt │ │ │ ├── WalletOwnerManagerImpl.kt │ │ │ └── WithdrawPersisterImpl.kt │ │ │ ├── model │ │ │ ├── CurrencyModel.kt │ │ │ ├── DepositModel.kt │ │ │ ├── ForbiddenPairModel.kt │ │ │ ├── RateModel.kt │ │ │ ├── ReservedTransferModel.kt │ │ │ ├── TransactionModel.kt │ │ │ ├── UserTransactionModel.kt │ │ │ ├── WalletConfigModel.kt │ │ │ ├── WalletLimitsModel.kt │ │ │ ├── WalletModel.kt │ │ │ ├── WalletOwnerModel.kt │ │ │ └── WithdrawModel.kt │ │ │ └── util │ │ │ └── Convertor.kt │ └── resources │ │ └── schema.sql │ └── test │ └── kotlin │ └── co │ └── nilin │ └── opex │ └── wallet │ └── ports │ └── postgres │ └── impl │ ├── CurrencyServiceTest.kt │ ├── WalletManagerTest.kt │ ├── WalletOwnerManagerTest.kt │ └── sample │ └── Samples.kt └── whitelist.txt /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /LICENSE-THIRD-PARTY: -------------------------------------------------------------------------------- 1 | The Opex source code itself does not bundle any third party libraries, but it 2 | depends on a number of libraries which carry their own copyright notices and 3 | license terms. These libraries are normally all linked static into the binary 4 | distributions of Opex: 5 | exchange-core/collection - https://github.com/exchange-core/collections/blob/master/LICENSE 6 | 7 | -------------------------------------------------------------------------------- /accountant/accountant-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 6 | -------------------------------------------------------------------------------- /accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/AccountantApp.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.app 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 5 | import org.springframework.boot.runApplication 6 | import org.springframework.context.annotation.ComponentScan 7 | 8 | @SpringBootApplication 9 | @ComponentScan("co.nilin.opex") 10 | class AccountantApp 11 | 12 | fun main(args: Array) { 13 | runApplication(*args) 14 | } -------------------------------------------------------------------------------- /accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/config/AppDispatchers.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.app.config 2 | 3 | import kotlinx.coroutines.asCoroutineDispatcher 4 | import java.util.concurrent.Executors 5 | 6 | object AppDispatchers { 7 | val kafkaExecutor = Executors.newSingleThreadExecutor().asCoroutineDispatcher() 8 | } -------------------------------------------------------------------------------- /accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/config/ErrorHandlerConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.app.config 2 | 3 | import co.nilin.opex.utility.error.EnableOpexErrorHandler 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @Configuration 7 | @EnableOpexErrorHandler 8 | class ErrorHandlerConfig { 9 | 10 | } -------------------------------------------------------------------------------- /accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/data/PairFeeResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.app.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class PairFeeResponse( 6 | val pair:String, 7 | val direction: String, 8 | val userLevel: String, 9 | val makerFee: BigDecimal, 10 | val takerFee: BigDecimal 11 | ) -------------------------------------------------------------------------------- /accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/utils/VaultUserIdMechanism.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.app.utils 2 | 3 | import org.springframework.vault.authentication.AppIdUserIdMechanism 4 | 5 | class VaultUserIdMechanism() : AppIdUserIdMechanism { 6 | override fun createUserId(): String { 7 | return System.getenv("BACKEND_USER") 8 | } 9 | } -------------------------------------------------------------------------------- /accountant/accountant-app/src/test/kotlin/co/nilin/opex/accountant/app/AccountantAppTest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.app 2 | 3 | import org.junit.jupiter.api.Test 4 | 5 | 6 | class AccountantAppTest : KafkaEnabledTest() { 7 | @Test 8 | fun contextLoad() { 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/api/FeeCalculator.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.api 2 | 3 | import co.nilin.opex.accountant.core.model.FeeFinancialActions 4 | import co.nilin.opex.accountant.core.model.FinancialAction 5 | import co.nilin.opex.accountant.core.model.Order 6 | import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent 7 | 8 | interface FeeCalculator { 9 | 10 | suspend fun createFeeActions( 11 | trade: TradeEvent, 12 | makerOrder: Order, 13 | takerOrder: Order, 14 | makerParentFA: FinancialAction?, 15 | takerParentFA: FinancialAction? 16 | ): FeeFinancialActions 17 | 18 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/api/FinancialActionJobManager.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.api 2 | 3 | interface FinancialActionJobManager { 4 | 5 | suspend fun processFinancialActions(offset: Long, size: Long) 6 | 7 | suspend fun retryFinancialActions(limit: Int) 8 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/api/TradeManager.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.api 2 | 3 | import co.nilin.opex.accountant.core.model.FinancialAction 4 | import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent 5 | 6 | interface TradeManager { 7 | suspend fun handleTrade(trade: TradeEvent): List 8 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/inout/FinancialActionEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.inout 2 | 3 | import co.nilin.opex.accountant.core.model.WalletType 4 | import java.math.BigDecimal 5 | import java.time.LocalDateTime 6 | 7 | data class FinancialActionEvent( 8 | val uuid: String, 9 | val symbol: String, 10 | val amount: BigDecimal, 11 | val sender: String, 12 | val senderWalletType: WalletType, 13 | val receiver: String, 14 | val receiverWalletType: WalletType, 15 | val createDate: LocalDateTime, 16 | val transferRef: String?, 17 | val description: String 18 | ) -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/inout/KycLevelUpdatedEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.inout 2 | 3 | 4 | import co.nilin.opex.accountant.core.model.KycLevel 5 | import java.time.LocalDateTime 6 | 7 | data class KycLevelUpdatedEvent(var userId: String, var kycLevel: KycLevel, var updateDate: LocalDateTime) 8 | -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/inout/RichOrderEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.inout 2 | 3 | interface RichOrderEvent -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/inout/RichOrderUpdate.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class RichOrderUpdate( 6 | val ouid: String, 7 | val price: BigDecimal, 8 | val quantity: BigDecimal, 9 | val remainedQuantity: BigDecimal, 10 | val status: OrderStatus = OrderStatus.NEW 11 | ) : RichOrderEvent { 12 | 13 | fun executedQuantity(): BigDecimal = quantity.minus(remainedQuantity) 14 | 15 | fun accumulativeQuoteQuantity(): BigDecimal = price.multiply((quantity.minus(remainedQuantity))) 16 | 17 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/model/FeeFinancialActions.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.model 2 | 3 | data class FeeFinancialActions( 4 | val makerFeeAction: FinancialAction, 5 | val takerFeeAction: FinancialAction 6 | ) -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/model/KycLevel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.model 2 | 3 | enum class KycLevel { 4 | Level1, Level2, 5 | } 6 | 7 | -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/model/PairConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | class PairConfig( 6 | val pair: String, 7 | val leftSideWalletSymbol: String, //can be same as pair left side 8 | val rightSideWalletSymbol: String, //can be same as pair right side 9 | val leftSideFraction: BigDecimal, 10 | val rightSideFraction: BigDecimal 11 | ) -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/model/PairFeeConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | class PairFeeConfig( 6 | val pairConfig: PairConfig, 7 | val direction: String, 8 | val userLevel: String, 9 | val makerFee: BigDecimal, 10 | val takerFee: BigDecimal 11 | ) -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/model/TempEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.model 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 4 | import java.time.LocalDateTime 5 | 6 | data class TempEvent(val id: Long, val ouid: String, val eventBody: CoreEvent, val eventDate: LocalDateTime) -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/model/WalletType.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.model 2 | 3 | enum class WalletType { 4 | 5 | MAIN, EXCHANGE 6 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/FinancialActionPublisher.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import co.nilin.opex.accountant.core.model.FinancialAction 4 | 5 | interface FinancialActionPublisher { 6 | suspend fun publish(fa: FinancialAction) 7 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/JsonMapper.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | interface JsonMapper { 4 | fun serialize(input: Any): String? 5 | fun deserialize(input: String, t: Class): T 6 | fun toMap(input: Any): Map 7 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/OrderPersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import co.nilin.opex.accountant.core.model.Order 4 | 5 | interface OrderPersister { 6 | suspend fun load(ouid: String): Order? 7 | suspend fun save(order: Order): Order 8 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/PairStaticRateLoader.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import java.math.BigDecimal 4 | 5 | interface PairStaticRateLoader { 6 | suspend fun calculateStaticRate(leftSide: String, rightSide: String): BigDecimal? 7 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/RichOrderPublisher.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import co.nilin.opex.accountant.core.inout.RichOrderEvent 4 | 5 | interface RichOrderPublisher { 6 | suspend fun publish(order: RichOrderEvent) 7 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/RichTradePublisher.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import co.nilin.opex.accountant.core.inout.RichTrade 4 | 5 | interface RichTradePublisher { 6 | suspend fun publish(trade: RichTrade) 7 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/TempEventPersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import co.nilin.opex.accountant.core.model.TempEvent 4 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 5 | 6 | interface TempEventPersister { 7 | suspend fun saveTempEvent(ouid: String, event: CoreEvent) 8 | suspend fun loadTempEvents(ouid: String): List 9 | suspend fun removeTempEvents(ouid: String) 10 | suspend fun removeTempEvents(tempEvents: List) 11 | suspend fun fetchTempEvents(offset: Long, size: Long): List 12 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/TempEventRepublisher.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 4 | 5 | interface TempEventRepublisher { 6 | suspend fun republish(events: List) 7 | } -------------------------------------------------------------------------------- /accountant/accountant-core/src/main/kotlin/co/nilin/opex/accountant/core/spi/UserLevelLoader.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.core.spi 2 | 3 | import co.nilin.opex.accountant.core.model.KycLevel 4 | 5 | interface UserLevelLoader { 6 | 7 | suspend fun load(uuid: String): String 8 | 9 | suspend fun update(uuid: String,userLevel:KycLevel) 10 | 11 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/consumer/EventKafkaListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.consumer 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.spi.EventListener 4 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class EventKafkaListener : EventConsumer() -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/consumer/FAResponseKafkaListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.consumer 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.inout.FinancialActionResponseEvent 4 | import co.nilin.opex.accountant.ports.kafka.listener.spi.FAResponseListener 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class FAResponseKafkaListener : EventConsumer() -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/consumer/OrderKafkaListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.consumer 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.inout.OrderRequestEvent 4 | import co.nilin.opex.accountant.ports.kafka.listener.spi.OrderSubmitRequestListener 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class OrderKafkaListener : EventConsumer() -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/consumer/TempEventKafkaListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.consumer 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.spi.TempEventListener 4 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class TempEventKafkaListener : EventConsumer() -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/consumer/TradeKafkaListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.consumer 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.spi.TradeListener 4 | import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class TradeKafkaListener : EventConsumer() -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/inout/FinancialActionResponseEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.inout 2 | 3 | import co.nilin.opex.accountant.core.model.FinancialActionStatus 4 | 5 | data class FinancialActionResponseEvent( 6 | val uuid: String, 7 | val status: FinancialActionStatus, 8 | val errorCode: Int?, 9 | val reason: String? 10 | ) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/inout/OrderCancelRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | class OrderCancelRequestEvent( 6 | ouid: String, 7 | uuid: String, 8 | pair: Pair, 9 | val orderId: Long 10 | ) : OrderRequestEvent(ouid, uuid, pair) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/inout/OrderRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | abstract class OrderRequestEvent(val ouid:String, val uuid: String, val pair: Pair) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/spi/EventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 4 | 5 | interface EventListener : Listener -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/spi/FAResponseListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.inout.FinancialActionResponseEvent 4 | 5 | interface FAResponseListener : Listener -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/spi/KycLevelUpdatedEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.accountant.core.inout.KycLevelUpdatedEvent 4 | 5 | 6 | interface KycLevelUpdatedEventListener { 7 | fun id(): String 8 | fun onEvent(event: KycLevelUpdatedEvent, partition: Int, offset: Long, timestamp: Long, eventId: String) 9 | 10 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/spi/Listener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.spi 2 | 3 | interface Listener { 4 | 5 | fun id(): String 6 | 7 | fun onEvent(event: T, partition: Int, offset: Long, timestamp: Long) 8 | 9 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/spi/OrderSubmitRequestListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.inout.OrderRequestEvent 4 | 5 | interface OrderSubmitRequestListener : Listener -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/spi/TempEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 4 | 5 | interface TempEventListener : Listener -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/listener/spi/TradeListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent 4 | 5 | interface TradeListener : Listener -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/test/kotlin/co/nilin/opex/accountant/ports/kafka/listener/consumer/ConsumerObject.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.consumer 2 | 3 | class ConsumerObject : EventConsumer() -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-eventlistener-kafka/src/test/kotlin/co/nilin/opex/accountant/ports/kafka/listener/consumer/ListenerObject.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.listener.consumer 2 | 3 | import co.nilin.opex.accountant.ports.kafka.listener.spi.Listener 4 | import org.slf4j.LoggerFactory 5 | 6 | class ListenerObject : Listener { 7 | 8 | private val logger = LoggerFactory.getLogger(ListenerObject::class.java) 9 | 10 | override fun id(): String { 11 | return "AnyListener" 12 | } 13 | 14 | override fun onEvent(event: Any, partition: Int, offset: Long, timestamp: Long) { 15 | logger.info("event called") 16 | } 17 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/dao/FinancialActionErrorRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.dao 2 | 3 | import co.nilin.opex.accountant.ports.postgres.model.FinancialActionErrorModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface FinancialActionErrorRepository : ReactiveCrudRepository { 9 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/dao/UserLevelMapperRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.dao 2 | 3 | import co.nilin.opex.accountant.ports.postgres.model.UserLevelMapperModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | import reactor.core.publisher.Mono 7 | 8 | @Repository 9 | interface UserLevelMapperRepository : ReactiveCrudRepository { 10 | 11 | fun findByUuid(uuid: String): Mono 12 | 13 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/model/FinancialActionErrorModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | import java.time.LocalDateTime 6 | 7 | @Table(name = "fi_action_error") 8 | data class FinancialActionErrorModel( 9 | val faId: Long, 10 | val error: String, 11 | val message: String?, 12 | val body: String?, 13 | val retryId: Long? = null, 14 | val date: LocalDateTime = LocalDateTime.now(), 15 | @Id var id: Long? = null 16 | ) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/model/FinancialActionRetryModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | import java.time.LocalDateTime 6 | 7 | @Table(name = "fi_action_retry") 8 | data class FinancialActionRetryModel( 9 | val faId: Long, 10 | var nextRunTime: LocalDateTime, 11 | var retries: Int = 0, 12 | var isResolved: Boolean = false, 13 | var hasGivenUp: Boolean = false, 14 | @Id var id: Long? = null 15 | ) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/model/PairFeeConfigModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.model 2 | 3 | import org.springframework.data.relational.core.mapping.Column 4 | import org.springframework.data.relational.core.mapping.Table 5 | import java.math.BigDecimal 6 | 7 | @Table("pair_fee_config") 8 | data class PairFeeConfigModel( 9 | val id: Long?, 10 | @Column("pair_config_id") val pairConfigId: String, 11 | @Column("direction") val direction: String, 12 | @Column("user_level") val userLevel: String, 13 | @Column("maker_fee") val makerFee: BigDecimal, 14 | @Column("taker_fee") val takerFee: BigDecimal 15 | ) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/model/TempEventModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Column 5 | import org.springframework.data.relational.core.mapping.Table 6 | import java.time.LocalDateTime 7 | 8 | @Table("temp_events") 9 | data class TempEventModel( 10 | @Id val id: Long?, 11 | val ouid: String, 12 | @Column("event_type") val eventType: String, 13 | @Column("event_body") val eventBody: String, 14 | @Column("event_date") val eventDate: LocalDateTime 15 | ) { 16 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/model/UserLevelMapperModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | 6 | @Table("user_level_mapper") 7 | data class UserLevelMapperModel( 8 | @Id val id: Long?, 9 | val uuid: String, 10 | val userLevel: String 11 | ) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-persister-postgres/src/main/kotlin/co/nilin/opex/accountant/ports/postgres/model/UserLevelModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | 6 | @Table("user_level") 7 | data class UserLevelModel(@Id val level: String) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-submitter-kafka/src/main/kotlin/co/nilin/opex/accountant/ports/kafka/submitter/service/EventPublisher.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.kafka.submitter.service 2 | 3 | interface EventPublisher { 4 | 5 | val topic: String 6 | 7 | } -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/data/Amount.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.walletproxy.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class Amount(val currency: Currency, val amount: BigDecimal) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/data/BooleanResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.walletproxy.data 2 | 3 | data class BooleanResponse(val result: Boolean) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/data/Currency.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.walletproxy.data 2 | 3 | data class Currency(val name: String, val symbol: String, val precision: Int) -------------------------------------------------------------------------------- /accountant/accountant-ports/accountant-wallet-proxy/src/main/kotlin/co/nilin/opex/accountant/ports/walletproxy/data/TransferResult.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.accountant.ports.walletproxy.data 2 | 3 | import co.nilin.opex.accountant.core.model.WalletType 4 | 5 | data class TransferResult( 6 | val date: Long, 7 | val sourceUuid: String, 8 | val sourceWalletType: WalletType, 9 | val sourceBalanceBeforeAction: Amount, 10 | val sourceBalanceAfterAction: Amount, 11 | val amount: Amount, 12 | val destUuid: String, 13 | val destWalletType: WalletType, 14 | val receivedAmount: Amount 15 | ) -------------------------------------------------------------------------------- /api/api-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:21 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --timeout=30s --start-period=60s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 6 | -------------------------------------------------------------------------------- /api/api-app/src/main/kotlin/co/nilin/opex/api/app/ApiApp.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.app 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.cache.annotation.EnableCaching 6 | import org.springframework.context.annotation.ComponentScan 7 | import org.springframework.scheduling.annotation.EnableScheduling 8 | import springfox.documentation.swagger2.annotations.EnableSwagger2 9 | 10 | @SpringBootApplication 11 | @ComponentScan("co.nilin.opex") 12 | @EnableScheduling 13 | class ApiApp 14 | 15 | fun main(args: Array) { 16 | runApplication(*args) 17 | } 18 | -------------------------------------------------------------------------------- /api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CacheConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.app.config 2 | 3 | import org.springframework.cache.CacheManager 4 | import org.springframework.cache.annotation.EnableCaching 5 | import org.springframework.cache.concurrent.ConcurrentMapCacheManager 6 | import org.springframework.context.annotation.Bean 7 | import org.springframework.context.annotation.Configuration 8 | 9 | @Configuration 10 | @EnableCaching 11 | class CacheConfig { 12 | 13 | @Bean 14 | fun apiKeyCacheManager(): CacheManager { 15 | return ConcurrentMapCacheManager("apiKey") 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /api/api-app/src/main/kotlin/co/nilin/opex/api/app/data/APIKeyResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.app.data 2 | 3 | import java.time.LocalDateTime 4 | import java.util.* 5 | 6 | data class APIKeyResponse( 7 | val label: String, 8 | val expirationTime: LocalDateTime?, 9 | val allowedIPs: String?, 10 | val key: String, 11 | val enabled: Boolean 12 | ) -------------------------------------------------------------------------------- /api/api-app/src/main/kotlin/co/nilin/opex/api/app/data/AccessTokenResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.app.data 2 | 3 | data class AccessTokenResponse( 4 | val access_token: String, 5 | val refresh_token: String, 6 | val expires_in: Long 7 | ) -------------------------------------------------------------------------------- /api/api-app/src/main/kotlin/co/nilin/opex/api/app/data/CreateAPIKeyRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.app.data 2 | 3 | data class CreateAPIKeyRequest( 4 | val label: String, 5 | val expiration: APIKeyExpiration?, 6 | val allowedIPs: String? 7 | ) -------------------------------------------------------------------------------- /api/api-app/src/main/kotlin/co/nilin/opex/api/app/utils/VaultUserIdMechanism.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.app.utils 2 | 3 | import org.springframework.vault.authentication.AppIdUserIdMechanism 4 | 5 | class VaultUserIdMechanism : AppIdUserIdMechanism { 6 | override fun createUserId(): String { 7 | return System.getenv("BACKEND_USER") 8 | } 9 | } -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/APIKey.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.time.LocalDateTime 4 | 5 | data class APIKey( 6 | val userId: String, 7 | val label: String, 8 | val accessToken: String?, 9 | val expirationTime: LocalDateTime?, 10 | val allowedIPs: String?, 11 | val key: String, 12 | val isEnabled: Boolean, 13 | val isExpired: Boolean 14 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AssignResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class AssignResponse( 4 | val addresses: List 5 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AssignedAddress.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class AddressType(val id: Long, val type: String, val addressRegex: String, val memoRegex: String?) 4 | data class Chain(val name: String, val addressTypes: List) 5 | data class AssignedAddress( 6 | val uuid: String, 7 | val address: String, 8 | val memo: String?, 9 | val type: AddressType, 10 | val chains: MutableList 11 | ) 12 | -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/BestPrice.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class BestPrice( 6 | val symbol: String, 7 | val bidPrice: BigDecimal?, 8 | val askPrice: BigDecimal?, 9 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/CandleData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | 6 | data class CandleData( 7 | val openTime: LocalDateTime, 8 | val closeTime: LocalDateTime, 9 | val open: BigDecimal, 10 | val close: BigDecimal, 11 | val high: BigDecimal, 12 | val low: BigDecimal, 13 | val volume: BigDecimal, 14 | val quoteAssetVolume: BigDecimal, 15 | val trades: Int, 16 | val takerBuyBaseAssetVolume: BigDecimal, 17 | val takerBuyQuoteAssetVolume: BigDecimal, 18 | ) 19 | -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/CountResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class CountResponse(val value: Long) 4 | -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/Currency.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class Currency(val symbol: String, val name: String) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/CurrencyImplementation.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class CurrencyImplementation( 6 | val currency: Currency, 7 | val implCurrency: Currency, 8 | val chain: Chain, 9 | val token: Boolean, 10 | val tokenAddress: String?, 11 | val tokenName: String?, 12 | val withdrawEnabled: Boolean, 13 | val withdrawFee: BigDecimal, 14 | val withdrawMin: BigDecimal, 15 | val decimal: Int 16 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/CurrencyRate.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class CurrencyRate( 6 | val base: String, 7 | val quote: String, 8 | val source: String, 9 | val rate: BigDecimal 10 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/DepositDetails.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class DepositDetails( 6 | val hash: String, 7 | val address: String, 8 | val memo: String?, 9 | val amount: BigDecimal, 10 | val chain: String, 11 | val isToken: Boolean, 12 | val tokenAddress: String? 13 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GlobalPrice.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class GlobalPrice( 4 | val symbol: String, 5 | val price: Float 6 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/MarketTrade.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.util.* 5 | 6 | data class MarketTrade( 7 | val symbol: String, 8 | val baseAsset: String, 9 | val quoteAsset: String, 10 | val id: Long, 11 | val price: BigDecimal, 12 | val quantity: BigDecimal, 13 | val quoteQuantity: BigDecimal, 14 | val time: Date, 15 | val isBestMatch: Boolean, 16 | val isMakerBuyer: Boolean 17 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/OrderBook.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class OrderBook( 6 | val price: BigDecimal?, 7 | val quantity: BigDecimal? 8 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/OrderMetaData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | enum class OrderDirection { 4 | ASK, BID 5 | } 6 | 7 | enum class MatchConstraint { 8 | GTC, 9 | IOC, 10 | IOC_BUDGET, 11 | FOK, 12 | FOK_BUDGET 13 | } 14 | 15 | enum class MatchingOrderType { 16 | LIMIT_ORDER, MARKET_ORDER 17 | } -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/OrderSubmitResult.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class OrderSubmitResult(val offset: Long?) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/OwnerLimitsResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class OwnerLimitsResponse( 4 | val canTrade: Boolean, 5 | val canWithdraw: Boolean, 6 | val canDeposit: Boolean 7 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/PairFeeResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class PairFeeResponse( 6 | val pair: String, 7 | val direction: String, 8 | val userLevel: String, 9 | val makerFee: BigDecimal, 10 | val takerFee: BigDecimal 11 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/PairInfoResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class PairInfoResponse( 6 | val pair: String, 7 | val leftSideWalletSymbol: String, 8 | val rightSideWalletSymbol: String, 9 | val leftSideFraction: BigDecimal, 10 | val rightSideFraction: BigDecimal 11 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/PriceStat.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class PriceStat( 6 | var symbol: String, 7 | val lastPrice: BigDecimal, 8 | val priceChangePercent: Double 9 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/PriceTicker.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | data class PriceTicker( 4 | var symbol: String?, 5 | val price: String? 6 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/Trade.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.util.* 5 | 6 | data class Trade( 7 | val symbol: String, 8 | val id: Long, 9 | val orderId: Long, 10 | val price: BigDecimal, 11 | val quantity: BigDecimal, 12 | val quoteQuantity: BigDecimal, 13 | val commission: BigDecimal, 14 | val commissionAsset: String, 15 | val time: Date, 16 | val isBuyer: Boolean, 17 | val isMaker: Boolean, 18 | val isBestMatch: Boolean, 19 | val isMakerBuyer: Boolean 20 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TradeVolumeStat.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TradeVolumeStat( 6 | var symbol: String, 7 | val volume: BigDecimal, 8 | val tradeCount: BigDecimal, 9 | val change: Double 10 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TransactionHistoryResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TransactionHistoryResponse( 6 | val id: Long, 7 | val currency: String, 8 | val amount: BigDecimal, 9 | val description: String?, 10 | val ref: String?, 11 | val date: Long 12 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/Wallet.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class Wallet( 6 | val asset: String, 7 | var balance: BigDecimal, 8 | var locked: BigDecimal, 9 | var withdraw: BigDecimal 10 | ) -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/APIKeyFilter.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.spi 2 | 3 | interface APIKeyFilter -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/AccountantProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.spi 2 | 3 | import co.nilin.opex.api.core.inout.PairFeeResponse 4 | import co.nilin.opex.api.core.inout.PairInfoResponse 5 | 6 | interface AccountantProxy { 7 | 8 | suspend fun getPairConfigs(): List 9 | 10 | suspend fun getFeeConfigs(): List 11 | 12 | suspend fun getFeeConfig(symbol: String): PairFeeResponse 13 | 14 | } -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/BlockchainGatewayProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.spi 2 | 3 | import co.nilin.opex.api.core.inout.AssignResponse 4 | import co.nilin.opex.api.core.inout.CurrencyImplementation 5 | import co.nilin.opex.api.core.inout.DepositDetails 6 | 7 | interface BlockchainGatewayProxy { 8 | 9 | suspend fun assignAddress(uuid: String, currency: String, chain: String): AssignResponse? 10 | 11 | suspend fun getDepositDetails(refs: List): List 12 | 13 | suspend fun getCurrencyImplementations(currency: String? = null): List 14 | 15 | } -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/GlobalMarketProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.spi 2 | 3 | import co.nilin.opex.api.core.inout.GlobalPrice 4 | 5 | interface GlobalMarketProxy { 6 | 7 | suspend fun getPrices(symbols: List): List 8 | 9 | } -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/MarketStatProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.spi 2 | 3 | import co.nilin.opex.api.core.inout.PriceStat 4 | import co.nilin.opex.api.core.inout.TradeVolumeStat 5 | import co.nilin.opex.common.utils.Interval 6 | 7 | interface MarketStatProxy { 8 | 9 | suspend fun getMostIncreasedInPricePairs(interval: Interval, limit: Int): List 10 | 11 | suspend fun getMostDecreasedInPricePairs(interval: Interval, limit: Int): List 12 | 13 | suspend fun getHighestVolumePair(interval: Interval): TradeVolumeStat? 14 | 15 | suspend fun getTradeCountPair(interval: Interval): TradeVolumeStat? 16 | 17 | } -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileGatewayProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.spi 2 | 3 | interface ProfileGatewayProxy { 4 | 5 | suspend fun getProfile() 6 | 7 | 8 | } -------------------------------------------------------------------------------- /api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/SymbolMapper.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.core.spi 2 | 3 | interface SymbolMapper { 4 | 5 | suspend fun fromInternalSymbol(symbol: String?): String? 6 | 7 | suspend fun toInternalSymbol(alias: String?): String? 8 | 9 | suspend fun symbolToAliasMap(): Map 10 | } 11 | -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/ErrorHandlerConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.config 2 | 3 | import co.nilin.opex.utility.error.EnableOpexErrorHandler 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @Configuration 7 | @EnableOpexErrorHandler 8 | class ErrorHandlerConfig { 9 | 10 | } -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/FiltersController.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.controller 2 | 3 | import org.springframework.web.bind.annotation.RestController 4 | 5 | @RestController 6 | class FiltersController 7 | -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/AccountInfoResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude 4 | 5 | @JsonInclude(JsonInclude.Include.NON_NULL) 6 | data class AccountInfoResponse( 7 | val makerCommission: Long, 8 | val takerCommission: Long, 9 | val buyerCommission: Long, 10 | val sellerCommission: Long, 11 | val canTrade: Boolean, 12 | val canWithdraw: Boolean, 13 | val canDeposit: Boolean, 14 | val updateTime: Long, 15 | val accountType: String, // Enum 16 | val balances: List, 17 | val permissions: List // Enum 18 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/AssetResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class AssetResponse( 6 | val asset: String, 7 | var free: BigDecimal, 8 | var locked: BigDecimal, 9 | var withdrawing: BigDecimal, 10 | var ipoable: BigDecimal = BigDecimal.ZERO, 11 | var valuation: BigDecimal = BigDecimal.ZERO 12 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/AssetsEstimatedValue.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class AssetsEstimatedValue( 6 | val value: BigDecimal, 7 | val evaluatedWith: String, 8 | val zeroValueAssets: List 9 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/AssignAddressResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | data class AssignAddressResponse( 4 | val address: String, 5 | val coin: String, 6 | val network: String, 7 | val tag: String, 8 | val url: String, 9 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/BalanceResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class BalanceResponse( 6 | var asset: String, 7 | var free: BigDecimal, 8 | var locked: BigDecimal, 9 | var withdraw: BigDecimal 10 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/CurrencyNetworkResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude 4 | import java.math.BigDecimal 5 | 6 | data class CurrencyNetworkResponse( 7 | val currency: String, 8 | val name: String, 9 | val chains: List 10 | ) 11 | 12 | @JsonInclude(JsonInclude.Include.NON_NULL) 13 | data class CurrencyNetwork( 14 | val network: String, 15 | val currency: String, 16 | val minWithdraw: BigDecimal, 17 | val withdrawFee: BigDecimal, 18 | val isToken: Boolean, 19 | val tokenAddress: String? 20 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/DepositResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class DepositResponse( 6 | val amount: BigDecimal, 7 | val coin: String, 8 | val network: String, 9 | val status: Int, 10 | val address: String, 11 | val addressTag: String?, 12 | val txId: String, 13 | val insertTime: Long, 14 | val transferType: Int, 15 | val unlockConfirm: String, 16 | val confirmTimes: String, 17 | val time: Long 18 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/ExchangeInfoResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import co.nilin.opex.api.core.inout.PairFeeResponse 4 | import java.util.* 5 | 6 | data class ExchangeInfoResponse( 7 | val timezone: String = TimeZone.getDefault().id, 8 | val serverTime: Long = Date().time, 9 | val rateLimits: List = RateLimit.values() 10 | .map { RateLimitResponse(it.rateLimitType, it.interval, it.intervalNum, it.limit) }, 11 | val exchangeFilters: List = emptyList(), 12 | val fees: List = emptyList(), 13 | val symbols: List 14 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/FillsData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class FillsData( 6 | val price: BigDecimal, 7 | val qty: BigDecimal, 8 | val commission: BigDecimal, 9 | val commissionAsset: String 10 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/GlobalPriceResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import co.nilin.opex.api.core.inout.CurrencyRate 4 | import co.nilin.opex.api.core.inout.GlobalPrice 5 | 6 | data class GlobalPriceResponse( 7 | val usdRate: List, 8 | val prices: List 9 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/MarketInfoResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | data class MarketInfoResponse( 4 | val activeUsers: Long, 5 | val totalOrders: Long, 6 | val totalTrades: Long 7 | ) 8 | -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/MarketStatResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import co.nilin.opex.api.core.inout.PriceStat 4 | import co.nilin.opex.api.core.inout.TradeVolumeStat 5 | 6 | data class MarketStatResponse( 7 | val mostIncreasedPrice: List, 8 | val mostDecreasedPrice: List, 9 | val mostVolume: TradeVolumeStat?, 10 | val mostTrades: TradeVolumeStat? 11 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/OrderBookResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class OrderBookResponse( 6 | val lastUpdateId: Long, 7 | val bids: List>, // Inner list -> [0]: PRICE, [1]: QTY 8 | val asks: List> // Inner list -> [0]: PRICE, [1]: QTY 9 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/PairFeeResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | data class PairFeeResponse( 4 | val symbol: String, 5 | val makerCommission: Double, 6 | val takerCommission: Double 7 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/RateLimit.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | enum class RateLimit(val rateLimitType: RateLimitType, val interval: String, val intervalNum: Int, val limit: Int) { 4 | 5 | REQUEST_WEIGHT(RateLimitType.REQUEST_WEIGHT, "MINUTE", 1, 1200), 6 | ORDERS_SECOND(RateLimitType.ORDERS, "SECOND", 10, 50), 7 | ORDERS_DAY(RateLimitType.ORDERS, "DAY", 1, 16000), 8 | RAW_REQUESTS(RateLimitType.RAW_REQUESTS, "MINUTE", 5, 6100) 9 | 10 | } -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/RateLimitResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | data class RateLimitResponse( 4 | val rateLimitType: RateLimitType, 5 | val interval: String, 6 | val intervalNum: Int, 7 | val limit: Int 8 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/RateLimitType.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | enum class RateLimitType { 4 | 5 | REQUEST_WEIGHT, 6 | ORDERS, 7 | RAW_REQUESTS 8 | 9 | } -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/RecentTradeResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class RecentTradeResponse( 6 | val id: Long, 7 | val price: BigDecimal, 8 | val qty: BigDecimal, 9 | val quoteQty: BigDecimal, 10 | val time: Long, 11 | val isBuyerMaker: Boolean, 12 | val isBestMatch: Boolean 13 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/data/WithdrawResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.data 2 | 3 | import java.math.BigDecimal 4 | 5 | data class WithdrawResponse( 6 | val address: String, 7 | val amount: BigDecimal, 8 | val applyTime: String, 9 | val coin: String, 10 | val id: String, 11 | val withdrawOrderId: String, 12 | val network: String, 13 | val transferType: Int, 14 | val status: Int, 15 | val transactionFee: String, 16 | val confirmNo: Int, 17 | val txId: String, 18 | val time: Long 19 | ) -------------------------------------------------------------------------------- /api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/util/SecurityExtension.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.binance.util 2 | 3 | import org.springframework.security.core.context.SecurityContext 4 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken 5 | 6 | fun SecurityContext.jwtAuthentication(): JwtAuthenticationToken { 7 | return authentication as JwtAuthenticationToken 8 | } 9 | 10 | fun JwtAuthenticationToken.tokenValue(): String { 11 | return this.token.tokenValue 12 | } -------------------------------------------------------------------------------- /api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/config/ErrorHandlerConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.opex.config 2 | 3 | import co.nilin.opex.utility.error.EnableOpexErrorHandler 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @Configuration 7 | @EnableOpexErrorHandler 8 | class ErrorHandlerConfig { 9 | 10 | } -------------------------------------------------------------------------------- /api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AccountController.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.opex.controller 2 | 3 | import co.nilin.opex.api.core.inout.* 4 | import co.nilin.opex.api.core.spi.MarketUserDataProxy 5 | import co.nilin.opex.api.core.spi.MatchingGatewayProxy 6 | import co.nilin.opex.api.core.spi.SymbolMapper 7 | import co.nilin.opex.api.core.spi.WalletProxy 8 | import org.springframework.web.bind.annotation.* 9 | 10 | 11 | @RestController 12 | class AccountController( 13 | 14 | ) {} -------------------------------------------------------------------------------- /api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/util/SecurityExtension.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.opex.util 2 | 3 | import org.springframework.security.core.context.SecurityContext 4 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken 5 | 6 | fun SecurityContext.jwtAuthentication(): JwtAuthenticationToken { 7 | return authentication as JwtAuthenticationToken 8 | } 9 | 10 | fun JwtAuthenticationToken.tokenValue(): String { 11 | return this.token.tokenValue 12 | } -------------------------------------------------------------------------------- /api/api-ports/api-persister-postgres/src/main/kotlin/co/nilin/opex/api/ports/postgres/model/SymbolMapModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | 6 | @Table("symbol_maps") 7 | class SymbolMapModel( 8 | @Id var id: Long?, 9 | val symbol: String, 10 | val aliasKey: String, 11 | val alias: String, 12 | ) 13 | -------------------------------------------------------------------------------- /api/api-ports/api-persister-postgres/src/test/kotlin/co/nilin/opex/api/ports/postgres/impl/sample/Samples.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.postgres.impl.sample 2 | 3 | import co.nilin.opex.api.ports.postgres.model.SymbolMapModel 4 | import java.security.Principal 5 | import java.time.LocalDateTime 6 | import java.time.ZoneOffset 7 | 8 | object VALID { 9 | 10 | const val ETH_USDT = "ETH_USDT" 11 | 12 | val SYMBOL_MAP_MODEL = SymbolMapModel( 13 | 1, 14 | ETH_USDT, 15 | "binance", 16 | ETH_USDT.replace("_", "") 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/config/ProxyDispatchers.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.config 2 | 3 | import kotlinx.coroutines.reactor.asCoroutineDispatcher 4 | import reactor.core.scheduler.Schedulers 5 | 6 | object ProxyDispatchers { 7 | 8 | val general = Schedulers.newBoundedElastic(10, 20, "general").asCoroutineDispatcher() 9 | val market = Schedulers.newBoundedElastic(30, 60, "market").asCoroutineDispatcher() 10 | val wallet = Schedulers.newBoundedElastic(10, 20, "wallet").asCoroutineDispatcher() 11 | } -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/AllOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | import java.util.* 4 | 5 | class AllOrderRequest( 6 | val symbol: String?, 7 | val startTime: Date?, 8 | val endTime: Date?, 9 | val limit: Int, //Default 500; max 1000. 10 | ) -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/AssignAddressRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | data class AssignAddressRequest( 4 | val uuid: String, 5 | val currency: String, 6 | val chain: String, 7 | ) -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/CancelOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | class CancelOrderRequest(val ouid: String, val uuid: String, val orderId: Long, val symbol: String) -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/CreateOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | import co.nilin.opex.api.core.inout.MatchConstraint 4 | import co.nilin.opex.api.core.inout.MatchingOrderType 5 | import co.nilin.opex.api.core.inout.OrderDirection 6 | import java.math.BigDecimal 7 | 8 | data class CreateOrderRequest( 9 | var uuid: String?, 10 | val pair: String, 11 | val price: BigDecimal, 12 | val quantity: BigDecimal, 13 | val direction: OrderDirection, 14 | val matchConstraint: MatchConstraint?, 15 | val orderType: MatchingOrderType, 16 | val userLevel: String 17 | ) -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/DepositDetailsRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | data class DepositDetailsRequest(val refs: List) -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/QueryOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | data class QueryOrderRequest( 4 | val symbol: String, 5 | val orderId: Long?, 6 | val origClientOrderId: String? 7 | ) -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/TradeRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | import java.util.* 4 | 5 | class TradeRequest( 6 | val symbol: String?, 7 | val fromTrade: Long?, 8 | val startTime: Date?, 9 | val endTime: Date?, 10 | val limit: Int //Default 500; max 1000. 11 | ) -------------------------------------------------------------------------------- /api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/data/TransactionRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.api.ports.proxy.data 2 | 3 | data class TransactionRequest( 4 | val coin: String?, 5 | val startTime: Long?=null, 6 | val endTime: Long?=null, 7 | val limit: Int, 8 | val offset: Int, 9 | val ascendingByTime: Boolean? = false 10 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 6 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/BCGatewayApp.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.context.annotation.ComponentScan 6 | import org.springframework.scheduling.annotation.EnableScheduling 7 | 8 | @SpringBootApplication 9 | @ComponentScan("co.nilin.opex") 10 | @EnableScheduling 11 | class BCGatewayApp 12 | 13 | fun main(args: Array) { 14 | runApplication(*args) 15 | } 16 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/config/AppDispatchers.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.config 2 | 3 | import kotlinx.coroutines.asCoroutineDispatcher 4 | import java.util.concurrent.Executors 5 | 6 | object AppDispatchers { 7 | val chainSyncExecutor = Executors.newFixedThreadPool(5).asCoroutineDispatcher() 8 | val walletSyncExecutor = Executors.newFixedThreadPool(2).asCoroutineDispatcher() 9 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/AddChainRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.dto 2 | 3 | data class AddChainRequest( 4 | val name: String?, 5 | val addressType: String?, 6 | val scannerEndpoint: String?, 7 | val scheduleDelaySeconds: Int, 8 | val scheduleErrorDelaySeconds: Int, 9 | ) { 10 | fun isValid(): Boolean { 11 | return !name.isNullOrEmpty() && !addressType.isNullOrEmpty() && scheduleDelaySeconds > 0 && scheduleErrorDelaySeconds > 0 12 | } 13 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/AddCurrencyRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class AddCurrencyRequest( 6 | var currencySymbol: String, 7 | var implementationSymbol: String, 8 | var currencyName:String, 9 | var newChain: String?=null, 10 | var tokenName: String?, 11 | var tokenAddress: String?, 12 | var isToken: Boolean? = false, 13 | var withdrawFee: BigDecimal, 14 | var minimumWithdraw: BigDecimal, 15 | var isWithdrawEnabled: Boolean? = true, 16 | var decimal: Int, 17 | var chain: String 18 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/AddressTypeRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.dto 2 | 3 | data class AddressTypeRequest( 4 | val name: String?, 5 | val addressRegex: String?, 6 | val memoRegex: String? 7 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/ChainEndpointRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.dto 2 | 3 | data class ChainEndpointRequest( 4 | val url: String, 5 | val username: String?, 6 | val password: String? 7 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/ChainResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.dto 2 | 3 | data class ChainResponse( 4 | val name: String, 5 | val addressTypes: List 6 | ) 7 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/TokenRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TokenRequest( 6 | val currencySymbol: String?, 7 | val implementationSymbol: String?, 8 | val chain: String?, 9 | val isToken: Boolean, 10 | val tokenName: String?, 11 | val tokenAddress: String?, 12 | val withdrawFee: BigDecimal, 13 | val minimumWithdraw: BigDecimal, 14 | val isWithdrawEnabled: Boolean = true, 15 | val decimal: Int = 18 16 | ) 17 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/TokenResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TokenResponse( 6 | val currency: String, 7 | val chain: String, 8 | val isToken: Boolean, 9 | val tokenAddress: String?, 10 | val tokenName: String?, 11 | val isWithdrawEnabled: Boolean, 12 | val withdrawFee: BigDecimal, 13 | val withdrawMin: BigDecimal, 14 | val decimal: Int 15 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/utils/VaultUserIdMechanism.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.app.utils 2 | 3 | import org.springframework.vault.authentication.AppIdUserIdMechanism 4 | 5 | class VaultUserIdMechanism() : AppIdUserIdMechanism { 6 | override fun createUserId(): String { 7 | return System.getenv("BACKEND_USER"); 8 | } 9 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/api/AssignAddressService.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.api 2 | 3 | import co.nilin.opex.bcgateway.core.model.AssignedAddress 4 | import co.nilin.opex.bcgateway.core.model.Currency 5 | 6 | interface AssignAddressService { 7 | suspend fun assignAddress(user: String, currency: Currency, chain: String): List 8 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/api/DepositService.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.api 2 | 3 | import co.nilin.opex.bcgateway.core.model.Deposit 4 | 5 | interface DepositService { 6 | suspend fun getDepositDetails(refs: List): List 7 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/api/InfoService.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.api 2 | 3 | import co.nilin.opex.bcgateway.core.model.CurrencyInfo 4 | 5 | interface InfoService { 6 | suspend fun countReservedAddresses(): Long 7 | suspend fun getCurrencyInfo(): CurrencyInfo 8 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/api/WalletSyncService.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.api 2 | 3 | import co.nilin.opex.bcgateway.core.model.Transfer 4 | 5 | interface WalletSyncService { 6 | suspend fun syncTransfers(transfers: List) 7 | } 8 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/AddressStatus.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | enum class AddressStatus { 4 | Assigned, Revoked, Reserved 5 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/AddressType.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | data class AddressType(val id: Long, val type: String, val addressRegex: String, val memoRegex: String?) 4 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Chain.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | data class Chain(val name: String, val addressTypes: List) 4 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Currency.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | data class Currency(val symbol: String, val name: String) 4 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyImplementation.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class CurrencyImplementation( 6 | val currency: Currency, 7 | val implCurrency: Currency, 8 | val chain: Chain, 9 | val token: Boolean, 10 | val tokenAddress: String?, 11 | val tokenName: String?, 12 | val withdrawEnabled: Boolean, 13 | val withdrawFee: BigDecimal, 14 | val withdrawMin: BigDecimal, 15 | val decimal: Int 16 | ) 17 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyInfo.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | data class CurrencyInfo(val currency: Currency, val implementations: List) 4 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Deposit.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | 6 | data class Deposit( 7 | val id: Long?, 8 | val hash: String, 9 | val depositor: String, 10 | val depositorMemo: String?, 11 | val amount: BigDecimal, 12 | val chain: String, 13 | val token: Boolean, 14 | val tokenAddress: String?, 15 | 16 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/ReservedAddress.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | data class ReservedAddress(val address: String, val memo: String?, val type: AddressType) 4 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Transfer.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | import java.math.BigDecimal 4 | import java.math.BigInteger 5 | 6 | data class Transfer( 7 | val txHash: String, 8 | val blockNumber: BigInteger, 9 | val receiver: Wallet, 10 | val isTokenTransfer: Boolean, 11 | val amount: BigDecimal, 12 | val chain: String, 13 | val tokenAddress: String? = null 14 | ) 15 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/Wallet.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | data class Wallet(val address: String, val memo: String? = null) 4 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/WithdrawData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class WithdrawData( 6 | val isEnabled: Boolean, 7 | val fee: BigDecimal, 8 | val minimum: BigDecimal 9 | ) 10 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/otc/LoginRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model.otc 2 | 3 | data class LoginRequest(var clientId:String, var clientSecret:String) 4 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/otc/LoginResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.model.otc 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | data class LoginResponse(var data: Token) 6 | 7 | data class Token(@JsonProperty("access_token") 8 | val accessToken: String, 9 | @JsonProperty("expires_in") 10 | val expireIn: Long) 11 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/service/DepositService.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.service 2 | 3 | import co.nilin.opex.bcgateway.core.api.DepositService 4 | import co.nilin.opex.bcgateway.core.model.Deposit 5 | import co.nilin.opex.bcgateway.core.spi.DepositHandler 6 | import org.springframework.stereotype.Service 7 | 8 | @Service 9 | class DepositServiceImpl(private val depositHandler: DepositHandler) : DepositService { 10 | override suspend fun getDepositDetails(refs: List): List { 11 | return depositHandler.findDepositsByHash(refs) 12 | } 13 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/service/InfoServiceImpl.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.service 2 | 3 | import co.nilin.opex.bcgateway.core.api.InfoService 4 | import co.nilin.opex.bcgateway.core.model.CurrencyInfo 5 | 6 | class InfoServiceImpl : InfoService { 7 | override suspend fun countReservedAddresses(): Long { 8 | TODO() 9 | } 10 | 11 | override suspend fun getCurrencyInfo(): CurrencyInfo { 12 | TODO() 13 | } 14 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/AddressManager.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.spi 2 | 3 | interface AddressManager { 4 | 5 | suspend fun revokeExpiredAddress() 6 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/AddressTypeHandler.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.spi 2 | 3 | import co.nilin.opex.bcgateway.core.model.AddressType 4 | 5 | interface AddressTypeHandler { 6 | 7 | suspend fun fetchAll(): List 8 | 9 | suspend fun addAddressType(name: String, addressRegex: String, memoRegex: String?) 10 | 11 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/AuthProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.spi 2 | 3 | 4 | import co.nilin.opex.bcgateway.core.model.otc.* 5 | 6 | interface AuthProxy { 7 | suspend fun getToken(loginRequest: LoginRequest):LoginResponse 8 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/ChainLoader.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.spi 2 | 3 | import co.nilin.opex.bcgateway.core.model.Chain 4 | 5 | interface ChainLoader { 6 | 7 | suspend fun addChain(name: String, addressType:String):Chain 8 | 9 | suspend fun fetchAllChains():List 10 | 11 | suspend fun fetchChainInfo(chain: String): Chain 12 | } 13 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/DepositHandler.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.spi 2 | 3 | import co.nilin.opex.bcgateway.core.model.Deposit 4 | 5 | interface DepositHandler { 6 | suspend fun findDepositsByHash(hash: List): List 7 | suspend fun saveAll(deposits: List) 8 | 9 | 10 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/ReservedAddressHandler.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.spi 2 | 3 | import co.nilin.opex.bcgateway.core.model.AddressType 4 | import co.nilin.opex.bcgateway.core.model.ReservedAddress 5 | 6 | interface ReservedAddressHandler { 7 | suspend fun addReservedAddress(list: List) 8 | suspend fun peekReservedAddress(addressType: AddressType): ReservedAddress? 9 | suspend fun remove(reservedAddress: ReservedAddress) 10 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/WalletProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.spi 2 | 3 | import java.math.BigDecimal 4 | 5 | interface WalletProxy { 6 | suspend fun transfer(uuid: String, symbol: String, amount: BigDecimal, hash: String, chain: String) 7 | } 8 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/utils/LoggerDelegate.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.core.utils 2 | 3 | import org.slf4j.Logger 4 | import org.slf4j.LoggerFactory 5 | import kotlin.properties.ReadOnlyProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class LoggerDelegate : ReadOnlyProperty { 9 | private lateinit var logger: Logger 10 | 11 | override operator fun getValue(thisRef: Any?, property: KProperty<*>): Logger { 12 | if (!::logger.isInitialized) logger = LoggerFactory.getLogger(thisRef!!.javaClass) 13 | return logger 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-core/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-eventlistener-kafka/src/main/kotlin/co/nilin/opex/bcgateway/ports/kafka/listener/model/AddCurrencyEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.kafka.listener.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class AddCurrencyEvent( 6 | val name: String, 7 | val symbol: String, 8 | val precision: BigDecimal 9 | ) : AdminEvent() -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-eventlistener-kafka/src/main/kotlin/co/nilin/opex/bcgateway/ports/kafka/listener/model/AdminEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.kafka.listener.model 2 | 3 | abstract class AdminEvent -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-eventlistener-kafka/src/main/kotlin/co/nilin/opex/bcgateway/ports/kafka/listener/model/DeleteCurrencyEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.kafka.listener.model 2 | 3 | data class DeleteCurrencyEvent(val name: String) : AdminEvent() -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-eventlistener-kafka/src/main/kotlin/co/nilin/opex/bcgateway/ports/kafka/listener/model/EditCurrencyEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.kafka.listener.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class EditCurrencyEvent( 6 | val name: String, 7 | val symbol: String, 8 | val precision: BigDecimal 9 | ) : AdminEvent() -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-eventlistener-kafka/src/main/kotlin/co/nilin/opex/bcgateway/ports/kafka/listener/spi/AdminEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.bcgateway.ports.kafka.listener.model.AdminEvent 4 | 5 | interface AdminEventListener { 6 | 7 | fun id(): String 8 | 9 | fun onEvent(event: AdminEvent, partition: Int, offset: Long, timestamp: Long) 10 | 11 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/AddressTypeRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.dao 2 | 3 | import co.nilin.opex.bcgateway.ports.postgres.model.AddressTypeModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | import reactor.core.publisher.Mono 7 | 8 | @Repository 9 | interface AddressTypeRepository : ReactiveCrudRepository { 10 | 11 | fun findByType(type: String): Mono 12 | 13 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/ChainAddressTypeRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.dao 2 | 3 | import co.nilin.opex.bcgateway.ports.postgres.model.ChainAddressTypeModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface ChainAddressTypeRepository : ReactiveCrudRepository -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/DepositRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.dao 2 | 3 | import co.nilin.opex.bcgateway.ports.postgres.model.DepositModel 4 | import kotlinx.coroutines.flow.Flow 5 | import org.springframework.data.r2dbc.repository.Query 6 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 7 | import org.springframework.stereotype.Repository 8 | 9 | @Repository 10 | interface DepositRepository : ReactiveCrudRepository { 11 | @Query("select * from deposits where hash in (:hash)") 12 | fun findAllByHash(hash: List): Flow 13 | } -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/AddressTypeModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Column 5 | import org.springframework.data.relational.core.mapping.Table 6 | 7 | @Table("address_types") 8 | data class AddressTypeModel( 9 | @Id val id: Long?, 10 | @Column("address_type") val type: String, 11 | @Column("address_regex") val addressRegex: String, 12 | @Column("memo_regex") val memoRegex: String? 13 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/AssignedAddressChainModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Column 5 | import org.springframework.data.relational.core.mapping.Table 6 | 7 | @Table("assigned_address_chains") 8 | data class AssignedAddressChainModel( 9 | @Id val id: Long?, 10 | @Column("assigned_address_id") val addressTypeId: Long, 11 | @Column("chain") val chain: String 12 | ) 13 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/ChainAddressTypeModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Column 5 | import org.springframework.data.relational.core.mapping.Table 6 | 7 | @Table("chain_address_types") 8 | data class ChainAddressTypeModel( 9 | @Id val id: Long?, @Column("chain_name") val chainName: String, @Column("addr_type_id") val addressTypeId: Long 10 | ) 11 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/ChainModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | 6 | @Table("chains") 7 | data class ChainModel(@Id val name: String) 8 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.model 2 | 3 | 4 | import org.springframework.data.annotation.Id 5 | import org.springframework.data.relational.core.mapping.Column 6 | import org.springframework.data.relational.core.mapping.Table 7 | 8 | @Table("currency") 9 | class CurrencyModel( 10 | @Id @Column("symbol") val symbol: String, 11 | @Column("name") var name: String 12 | ) 13 | -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/ReservedAddressModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.postgres.model 2 | 3 | import org.springframework.data.relational.core.mapping.Column 4 | import org.springframework.data.relational.core.mapping.Table 5 | 6 | @Table("reserved_addresses") 7 | data class ReservedAddressModel( 8 | val id: Long?, 9 | val address: String, 10 | val memo: String?, 11 | @Column("address_type") val type: Long 12 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-wallet-proxy/src/main/kotlin/co/nilin/opex/bcgateway/ports/walletproxy/model/Amount.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.walletproxy.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class Amount(val currency: Currency, val amount: BigDecimal) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-wallet-proxy/src/main/kotlin/co/nilin/opex/bcgateway/ports/walletproxy/model/Currency.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.walletproxy.model 2 | 3 | data class Currency( 4 | val symbol: String, 5 | val name: String, 6 | val precision: Int, 7 | ) -------------------------------------------------------------------------------- /bc-gateway/bc-gateway-ports/bc-gateway-wallet-proxy/src/main/kotlin/co/nilin/opex/bcgateway/ports/walletproxy/model/TransferResult.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.bcgateway.ports.walletproxy.model 2 | 3 | data class TransferResult( 4 | val date: Long, 5 | val sourceUuid: String, 6 | val sourceWalletType: String, 7 | val sourceBalanceBeforeAction: Amount, 8 | val sourceBalanceAfterAction: Amount, 9 | val amount: Amount, 10 | val destUuid: String, 11 | val destWalletType: String, 12 | val receivedAmount: Amount 13 | ) 14 | -------------------------------------------------------------------------------- /common/src/main/kotlin/co/nilin/opex/common/CommonErrorConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.common 2 | 3 | import co.nilin.opex.utility.error.data.ErrorRep 4 | import co.nilin.opex.utility.error.spi.ErrorConfig 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class CommonErrorConfig : ErrorConfig { 9 | 10 | override fun findErrorByCode(code: Int?): ErrorRep? { 11 | return OpexError.findByCode(code) 12 | } 13 | 14 | override fun internalServerError(): ErrorRep { 15 | return OpexError.InternalServerError 16 | } 17 | 18 | override fun invalidRequestParamError(): ErrorRep { 19 | return OpexError.InvalidRequestParam 20 | } 21 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/co/nilin/opex/common/utils/Extensions.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.common.utils 2 | 3 | fun justTry(action: () -> Unit) { 4 | try { 5 | action() 6 | } catch (_: Exception) { 7 | } 8 | } -------------------------------------------------------------------------------- /docker-compose-otc.build.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | 4 | postgres-opex: 5 | image: ghcr.io/opexdev/postgres-opex:${TAG} 6 | build: docker-images/postgres 7 | wallet: 8 | image: ghcr.io/opexdev/wallet:${TAG} 9 | build: wallet/wallet-app 10 | vault: 11 | image: ghcr.io/opexdev/vault-opex:${TAG} 12 | build: docker-images/vault 13 | bc-gateway: 14 | image: ghcr.io/opexdev/bc-gateway:${TAG} 15 | build: bc-gateway/bc-gateway-app -------------------------------------------------------------------------------- /docker-compose-otc.local.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | 4 | postgres-wallet: 5 | ports: 6 | - "5435:5432" 7 | 8 | wallet: 9 | ports: 10 | - "127.0.0.1:8091:8080" 11 | - "127.0.0.1:1049:5005" 12 | vault: 13 | ports: 14 | - "8200:8200" 15 | bc-gateway: 16 | ports: 17 | - "0.0.0.0:8095:8080" 18 | - "127.0.0.1:1052:5005" 19 | postgres-bc-gateway: 20 | ports: 21 | - "5437:5432" 22 | 23 | 24 | -------------------------------------------------------------------------------- /docker-compose-otc.override.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | 4 | postgres-opex: 5 | image: ghcr.io/opexdev/postgres-opex 6 | build: docker-images/postgres 7 | 8 | wallet: 9 | build: wallet/wallet-app 10 | volumes: 11 | - "./preferences-dev.yml:/preferences.yml" 12 | - "./drive-key.json:/drive-key.json" 13 | vault: 14 | build: docker-images/vault 15 | 16 | bc-gateway: 17 | build: bc-gateway/bc-gateway-app 18 | volumes: 19 | - "./preferences-dev.yml:/preferences.yml" 20 | 21 | -------------------------------------------------------------------------------- /docker-images/kafka/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM confluentinc/cp-kafka:7.1.1 2 | USER root 3 | RUN mkdir /opt/prometheus 4 | RUN chmod +rx /opt/prometheus 5 | COPY jmx-exporter-0.16.1.jar /opt/prometheus/jmx-exporter.jar 6 | COPY kafka-jmx-exporter.yml /opt/prometheus -------------------------------------------------------------------------------- /docker-images/kafka/jmx-exporter-0.16.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opexdev/core/0889d8cfe651a90bf231e55cd5c1a324436ade95/docker-images/kafka/jmx-exporter-0.16.1.jar -------------------------------------------------------------------------------- /docker-images/postgres/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:14-alpine 2 | COPY ["add-backup-user.sh", "/docker-entrypoint-initdb.d/"] 3 | EXPOSE 5432 4 | HEALTHCHECK --interval=15s --start-period=30s --retries=15 CMD pg_isready -U $POSTGRES_USER -d $POSTGRES_DB -q || exit 1 5 | -------------------------------------------------------------------------------- /docker-images/postgres/add-backup-user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL 5 | CREATE USER $POSTGRES_READ_ONLY_USER WITH ENCRYPTED PASSWORD '$POSTGRES_READ_ONLY_PASSWORD'; 6 | GRANT CONNECT ON DATABASE $POSTGRES_DB TO $POSTGRES_READ_ONLY_USER; 7 | GRANT USAGE ON SCHEMA public TO $POSTGRES_READ_ONLY_USER; 8 | ALTER DEFAULT PRIVILEGES IN SCHEMA public 9 | GRANT SELECT ON TABLES TO $POSTGRES_READ_ONLY_USER; 10 | ALTER DEFAULT PRIVILEGES IN SCHEMA public 11 | GRANT SELECT ON SEQUENCES TO $POSTGRES_READ_ONLY_USER; 12 | EOSQL 13 | -------------------------------------------------------------------------------- /docker-images/vault/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM vault:1.11.7 2 | COPY [ "workflow-vault.sh", "backend-policy.hcl", "panel-policy.hcl", "vault.json", "/vault/config/"] 3 | #COPY --chmod=777 workflow-vault.sh /vault/config/ 4 | EXPOSE 8200 5 | #RUN ["chmod", "+x", "/vault/config/workflow-vault.sh"] 6 | RUN sed -i 's/\r$//' /vault/config/workflow-vault.sh && \ 7 | chmod +x /vault/config/workflow-vault.sh 8 | ENTRYPOINT /vault/config/workflow-vault.sh 9 | HEALTHCHECK --interval=15s --start-period=15s --retries=15 CMD wget -qO- http://localhost:8200/v1/sys/health &>/dev/null || exit 1 -------------------------------------------------------------------------------- /docker-images/vault/backend-policy.hcl: -------------------------------------------------------------------------------- 1 | path "kv/*" { 2 | capabilities = ["read"] 3 | } 4 | 5 | path "secret/*" { 6 | capabilities = ["read"] 7 | } 8 | 9 | path "secret/opex/" { 10 | capabilities = ["read"] 11 | } 12 | 13 | path "secret/opex-wallet/" { 14 | capabilities = ["read"] 15 | } 16 | 17 | path "sys/mounts" { 18 | capabilities = ["read"] 19 | } 20 | 21 | path "sys/auth" { 22 | capabilities = ["read"] 23 | } 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docker-images/vault/panel-policy.hcl: -------------------------------------------------------------------------------- 1 | path "kv/*" { 2 | capabilities = ["create", "read", "update", "delete", "list"] 3 | } 4 | 5 | path "secret/*" { 6 | capabilities = ["create", "read", "update", "delete", "list"] 7 | } 8 | 9 | path "secret/opex/" { 10 | capabilities = ["create", "read", "update", "delete", "list"] 11 | } 12 | 13 | path "secret/opex-wallet/" { 14 | capabilities = ["create", "read", "update", "delete", "list"] 15 | } 16 | 17 | 18 | path "sys/mounts" { 19 | capabilities = ["create", "read", "update", "delete", "list"] 20 | } 21 | 22 | path "sys/auth" { 23 | capabilities = ["create", "read", "update", "delete", "list"] 24 | } 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /docker-images/vault/vault.json: -------------------------------------------------------------------------------- 1 | { 2 | "listener": { 3 | "tcp": { 4 | "address": "0.0.0.0:8200", 5 | "tls_disable": "true" 6 | } 7 | }, 8 | "backend": { 9 | "file": { 10 | "path": "/vault/file" 11 | } 12 | }, 13 | "default_lease_ttl": "168h", 14 | "max_lease_ttl": "0h", 15 | "api_addr": "http://0.0.0.0:8200", 16 | "ui": true 17 | } 18 | -------------------------------------------------------------------------------- /eventlog/eventlog-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 6 | -------------------------------------------------------------------------------- /eventlog/eventlog-app/src/main/kotlin/co/nilin/opex/eventlog/app/EventLogApp.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.app 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.context.annotation.ComponentScan 6 | import org.springframework.scheduling.annotation.EnableScheduling 7 | 8 | @SpringBootApplication 9 | @ComponentScan("co.nilin.opex") 10 | @EnableScheduling 11 | class EventLogApp 12 | 13 | fun main(args: Array) { 14 | runApplication(*args) 15 | } -------------------------------------------------------------------------------- /eventlog/eventlog-app/src/main/kotlin/co/nilin/opex/util/vault/VaultUserIdMechanism.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.util.vault 2 | 3 | import org.springframework.vault.authentication.AppIdUserIdMechanism 4 | 5 | class VaultUserIdMechanism() : AppIdUserIdMechanism { 6 | override fun createUserId(): String { 7 | return System.getenv("BACKEND_USER") 8 | } 9 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/inout/DeadLetterEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.inout 2 | 3 | import java.time.LocalDateTime 4 | 5 | data class DeadLetterEvent( 6 | val originModule: String, 7 | val originTopic: String?, 8 | val consumerGroup: String?, 9 | val exceptionMessage: String?, 10 | val exceptionStacktrace: String?, 11 | val exceptionClassName: String?, 12 | val value: String?, 13 | val timestamp: LocalDateTime, 14 | ) -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/inout/OriginModule.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.inout 2 | 3 | enum class OriginModule { 4 | 5 | ACCOUNTANT, API, MATCHING_ENGINE, WALLET, WEBSOCKET 6 | 7 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/DeadLetter.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | interface DeadLetter { 4 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/DeadLetterPersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | import co.nilin.opex.eventlog.core.inout.DeadLetterEvent 4 | 5 | interface DeadLetterPersister { 6 | 7 | suspend fun save(event: DeadLetterEvent) 8 | 9 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/Event.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | interface Event { 4 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/EventPersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 4 | 5 | interface EventPersister { 6 | suspend fun saveEvent(event: CoreEvent): List 7 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/Order.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | interface Order { 4 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/OrderPersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.* 4 | 5 | interface OrderPersister { 6 | suspend fun submitOrder(orderEvent: SubmitOrderEvent) 7 | suspend fun rejectOrder(orderEvent: RejectOrderEvent) 8 | suspend fun saveOrder(orderEvent: CreateOrderEvent) 9 | suspend fun updateOrder(orderEvent: UpdatedOrderEvent) 10 | suspend fun cancelOrder(orderEvent: CancelOrderEvent) 11 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/Trade.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | interface Trade { 4 | } -------------------------------------------------------------------------------- /eventlog/eventlog-core/src/main/kotlin/co/nilin/opex/eventlog/core/spi/TradePersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.core.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent 4 | 5 | interface TradePersister { 6 | suspend fun saveTrade(tradeEvent: TradeEvent): Trade 7 | } -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-eventlistener-kafka/src/main/kotlin/co/nilin/opex/eventlog/ports/kafka/listener/inout/OrderCancelRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.kafka.listener.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | class OrderCancelRequestEvent( 6 | ouid: String, 7 | uuid: String, 8 | pair: Pair, 9 | val orderId: Long 10 | ) : OrderRequestEvent(ouid, uuid, pair) -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-eventlistener-kafka/src/main/kotlin/co/nilin/opex/eventlog/ports/kafka/listener/inout/OrderRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.kafka.listener.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | abstract class OrderRequestEvent(val ouid:String, val uuid: String, val pair: Pair) -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-eventlistener-kafka/src/main/kotlin/co/nilin/opex/eventlog/ports/kafka/listener/spi/DLTListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.kafka.listener.spi 2 | 3 | import org.apache.kafka.common.header.Headers 4 | 5 | interface DLTListener { 6 | fun id(): String 7 | fun onEvent(event: String?, partition: Int, offset: Long, timestamp: Long, headers: Headers) 8 | } -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-eventlistener-kafka/src/main/kotlin/co/nilin/opex/eventlog/ports/kafka/listener/spi/EventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 4 | 5 | interface EventListener { 6 | fun id(): String 7 | fun onEvent(coreEvent: CoreEvent, partition: Int, offset: Long, timestamp: Long) 8 | } -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-eventlistener-kafka/src/main/kotlin/co/nilin/opex/eventlog/ports/kafka/listener/spi/OrderSubmitRequestListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.eventlog.ports.kafka.listener.inout.OrderRequestEvent 4 | 5 | interface OrderSubmitRequestListener { 6 | fun id(): String 7 | suspend fun onOrder(order: OrderRequestEvent, partition: Int, offset: Long, timestamp: Long) 8 | } -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-eventlistener-kafka/src/main/kotlin/co/nilin/opex/eventlog/ports/kafka/listener/spi/TradeListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent 4 | 5 | interface TradeListener { 6 | fun id(): String 7 | fun onTrade(tradeEvent: TradeEvent, partition: Int, offset: Long, timestamp: Long) 8 | } -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-persister-postgres/src/main/kotlin/co/nilin/opex/eventlog/ports/postgres/dao/DeadLetterEventRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.postgres.dao 2 | 3 | import co.nilin.opex.eventlog.ports.postgres.model.DeadLetterEventModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface DeadLetterEventRepository : ReactiveCrudRepository { 9 | } -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-persister-postgres/src/main/kotlin/co/nilin/opex/eventlog/ports/postgres/dao/EventRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.postgres.dao 2 | 3 | import co.nilin.opex.eventlog.ports.postgres.model.EventModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface EventRepository : ReactiveCrudRepository 9 | -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-persister-postgres/src/main/kotlin/co/nilin/opex/eventlog/ports/postgres/dao/OrderEventRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.postgres.dao 2 | 3 | import co.nilin.opex.eventlog.ports.postgres.model.OrderEventsModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface OrderEventRepository : ReactiveCrudRepository 9 | -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-persister-postgres/src/main/kotlin/co/nilin/opex/eventlog/ports/postgres/dao/OrderRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.postgres.dao 2 | 3 | import co.nilin.opex.eventlog.ports.postgres.model.OrderModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface OrderRepository : ReactiveCrudRepository 9 | -------------------------------------------------------------------------------- /eventlog/eventlog-ports/eventlog-persister-postgres/src/main/kotlin/co/nilin/opex/eventlog/ports/postgres/dao/TradeRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.eventlog.ports.postgres.dao 2 | 3 | import co.nilin.opex.eventlog.ports.postgres.model.TradeModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface TradeRepository : ReactiveCrudRepository 9 | -------------------------------------------------------------------------------- /market/market-app/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /market/market-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 -------------------------------------------------------------------------------- /market/market-app/src/main/kotlin/co/nilin/opex/market/app/MarketAppApplication.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.app 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.context.annotation.ComponentScan 6 | import org.springframework.scheduling.annotation.EnableScheduling 7 | 8 | @SpringBootApplication 9 | @ComponentScan("co.nilin.opex") 10 | @EnableScheduling 11 | class MarketAppApplication 12 | 13 | fun main(args: Array) { 14 | runApplication(*args) 15 | } 16 | -------------------------------------------------------------------------------- /market/market-app/src/main/kotlin/co/nilin/opex/market/app/config/AppDispatchers.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.app.config 2 | 3 | import kotlinx.coroutines.asCoroutineDispatcher 4 | import java.util.concurrent.Executors 5 | 6 | object AppDispatchers { 7 | val kafkaExecutor = Executors.newSingleThreadExecutor().asCoroutineDispatcher() 8 | } -------------------------------------------------------------------------------- /market/market-app/src/main/kotlin/co/nilin/opex/market/app/data/CountResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.app.data 2 | 3 | data class CountResponse(val value: Long) -------------------------------------------------------------------------------- /market/market-app/src/main/kotlin/co/nilin/opex/market/app/utils/Extensions.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.app.utils 2 | 3 | import java.time.LocalDateTime 4 | import java.time.ZoneId 5 | import java.util.* 6 | 7 | fun LocalDateTime.asDate(): Date { 8 | return Date.from(atZone(ZoneId.systemDefault()).toInstant()) 9 | } 10 | 11 | fun Date.asLocalDateTime(): LocalDateTime { 12 | return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()) 13 | } 14 | 15 | fun Long.asLocalDateTime(): LocalDateTime { 16 | return LocalDateTime.ofInstant(Date(this).toInstant(), ZoneId.systemDefault()) 17 | } -------------------------------------------------------------------------------- /market/market-app/src/main/kotlin/co/nilin/opex/market/app/utils/VaultUserIdMechanism.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.app.utils 2 | 3 | import org.springframework.vault.authentication.AppIdUserIdMechanism 4 | 5 | class VaultUserIdMechanism : AppIdUserIdMechanism { 6 | override fun createUserId(): String { 7 | return System.getenv("BACKEND_USER") 8 | } 9 | } -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/event/RichOrderEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.event 2 | 3 | interface RichOrderEvent -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/event/RichOrderUpdate.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.event 2 | 3 | import co.nilin.opex.market.core.inout.OrderStatus 4 | import java.math.BigDecimal 5 | 6 | data class RichOrderUpdate( 7 | val ouid: String, 8 | val price: BigDecimal, 9 | val quantity: BigDecimal, 10 | val remainedQuantity: BigDecimal, 11 | val status: OrderStatus = OrderStatus.NEW 12 | ) : RichOrderEvent { 13 | 14 | fun executedQuantity(): BigDecimal = quantity.minus(remainedQuantity) 15 | 16 | fun accumulativeQuoteQuantity(): BigDecimal = price.multiply((quantity.minus(remainedQuantity))) 17 | 18 | } -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/AggregatedOrderPriceModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class AggregatedOrderPriceModel( 6 | val price: BigDecimal?, 7 | val quantity: BigDecimal? 8 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/AllOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.util.* 4 | 5 | class AllOrderRequest( 6 | val symbol: String?, 7 | val startTime: Date?, 8 | val endTime: Date?, 9 | val limit: Int 10 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/BestPrice.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class BestPrice( 6 | val symbol: String, 7 | val bidPrice: BigDecimal?, 8 | val askPrice: BigDecimal?, 9 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/CandleData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | 6 | data class CandleData( 7 | val openTime: LocalDateTime, 8 | val closeTime: LocalDateTime, 9 | val open: BigDecimal, 10 | val close: BigDecimal, 11 | val high: BigDecimal, 12 | val low: BigDecimal, 13 | val volume: BigDecimal, 14 | val quoteAssetVolume: BigDecimal, 15 | val trades: Int, 16 | val takerBuyBaseAssetVolume: BigDecimal, 17 | val takerBuyQuoteAssetVolume: BigDecimal, 18 | ) 19 | -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/CurrencyRate.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class CurrencyRate( 6 | val base: String, 7 | val quote: String, 8 | val source: RateSource, 9 | val rate: BigDecimal 10 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/MarketTrade.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.util.* 5 | 6 | data class MarketTrade( 7 | val symbol: String, 8 | val baseAsset: String, 9 | val quoteAsset: String, 10 | val id: Long, 11 | val price: BigDecimal, 12 | val quantity: BigDecimal, 13 | val quoteQuantity: BigDecimal, 14 | val time: Date, 15 | val isBestMatch: Boolean, 16 | val isMakerBuyer: Boolean 17 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/OrderBook.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class OrderBook( 6 | val price: BigDecimal?, 7 | val quantity: BigDecimal? 8 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/OrderMetaData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | enum class OrderDirection { 4 | ASK, BID 5 | } 6 | 7 | enum class MatchConstraint { 8 | GTC, 9 | IOC, 10 | IOC_BUDGET, 11 | FOK, 12 | FOK_BUDGET 13 | } 14 | 15 | enum class MatchingOrderType { 16 | LIMIT_ORDER, MARKET_ORDER 17 | } -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/PriceStat.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class PriceStat( 6 | val symbol: String, 7 | val lastPrice: BigDecimal, 8 | val priceChangePercent: Double 9 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/PriceTicker.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | data class PriceTicker( 4 | val symbol: String?, 5 | val price: String? 6 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/QueryOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | data class QueryOrderRequest( 4 | val symbol: String, 5 | val orderId: Long?, 6 | val origClientOrderId: String? 7 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/RateSource.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | enum class RateSource { 4 | MARKET, EXTERNAL 5 | } -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Trade.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.util.* 5 | 6 | data class Trade( 7 | val symbol: String, 8 | val id: Long, 9 | val orderId: Long, 10 | val price: BigDecimal, 11 | val quantity: BigDecimal, 12 | val quoteQuantity: BigDecimal, 13 | val commission: BigDecimal, 14 | val commissionAsset: String, 15 | val time: Date, 16 | val isBuyer: Boolean, 17 | val isMaker: Boolean, 18 | val isBestMatch: Boolean, 19 | val isMakerBuyer: Boolean 20 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TradeRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.util.* 4 | 5 | class TradeRequest( 6 | val symbol: String?, 7 | val fromTrade: Long?, 8 | val startTime: Date?, 9 | val endTime: Date?, 10 | val limit: Int 11 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TradeVolumeStat.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TradeVolumeStat( 6 | val symbol: String, 7 | val volume: BigDecimal, 8 | val tradeCount: BigDecimal, 9 | val change: Double 10 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/Transaction.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | 6 | data class Transaction( 7 | var createDate: LocalDateTime, 8 | var volume: BigDecimal, 9 | val transactionPrice: BigDecimal, 10 | var matchedPrice: BigDecimal, 11 | var side: String, 12 | var symbol: String, 13 | var fee: BigDecimal, 14 | var user: String?=null 15 | ) 16 | 17 | data class TxOfTrades(var transactions:List?) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | data class TransactionRequest( 4 | val coin: String?, 5 | val category: String?, 6 | val startTime: Long? = null, 7 | val endTime: Long? = null, 8 | val limit: Int? = 10, 9 | val offset: Int? = 0, 10 | val ascendingByTime: Boolean? = false, 11 | var owner: String? = null 12 | ) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/inout/TransactionResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.inout 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | import java.util.Date 6 | 7 | 8 | data class TransactionDto( 9 | var createDate: Date, 10 | var volume: BigDecimal, 11 | val transactionPrice: BigDecimal, 12 | var matchedPrice: BigDecimal, 13 | var side: String, 14 | var symbol: String, 15 | var fee: BigDecimal, 16 | var user: String?=null 17 | ) 18 | 19 | data class TransactionResponse(var transactions:List?) -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/MarketRateService.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.spi 2 | 3 | import co.nilin.opex.market.core.inout.CurrencyRate 4 | import co.nilin.opex.market.core.inout.RateSource 5 | 6 | interface MarketRateService { 7 | 8 | suspend fun currencyRate(quote: String, source: RateSource): List 9 | 10 | suspend fun currencyRate(base: String, quote: String, source: RateSource): CurrencyRate 11 | 12 | } -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/OrderPersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.spi 2 | 3 | import co.nilin.opex.market.core.event.RichOrder 4 | import co.nilin.opex.market.core.event.RichOrderUpdate 5 | import co.nilin.opex.market.core.inout.Order 6 | 7 | interface OrderPersister { 8 | 9 | suspend fun save(order: RichOrder) 10 | 11 | suspend fun update(orderUpdate: RichOrderUpdate) 12 | 13 | suspend fun load(ouid: String): Order? 14 | } -------------------------------------------------------------------------------- /market/market-core/src/main/kotlin/co/nilin/opex/market/core/spi/TradePersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.core.spi 2 | 3 | import co.nilin.opex.market.core.event.RichTrade 4 | 5 | interface TradePersister { 6 | suspend fun save(trade: RichTrade) 7 | } -------------------------------------------------------------------------------- /market/market-ports/market-eventlistener-kafka/src/main/kotlin/co/nilin/opex/market/ports/kafka/listener/spi/RichOrderListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.market.core.event.RichOrderEvent 4 | 5 | interface RichOrderListener { 6 | 7 | fun id(): String 8 | 9 | fun onOrder(order: RichOrderEvent, partition: Int, offset: Long, timestamp: Long) 10 | 11 | } -------------------------------------------------------------------------------- /market/market-ports/market-eventlistener-kafka/src/main/kotlin/co/nilin/opex/market/ports/kafka/listener/spi/RichTradeListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.market.core.event.RichTrade 4 | 5 | interface RichTradeListener { 6 | 7 | fun id(): String 8 | 9 | fun onTrade(trade: RichTrade, partition: Int, offset: Long, timestamp: Long) 10 | } -------------------------------------------------------------------------------- /market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/model/CandleInfoData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.ports.postgres.model 2 | 3 | import org.springframework.data.relational.core.mapping.Column 4 | import java.math.BigDecimal 5 | import java.time.LocalDateTime 6 | 7 | data class CandleInfoData( 8 | val openTime: LocalDateTime, 9 | val closeTime: LocalDateTime, 10 | val open: BigDecimal?, 11 | val close: BigDecimal?, 12 | val high: BigDecimal?, 13 | val low: BigDecimal?, 14 | val volume: BigDecimal?, 15 | val trades: Int, 16 | ) -------------------------------------------------------------------------------- /market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/model/CurrencyRateModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.ports.postgres.model 2 | 3 | import co.nilin.opex.market.core.inout.RateSource 4 | import org.springframework.data.annotation.Id 5 | import org.springframework.data.relational.core.mapping.Table 6 | import java.math.BigDecimal 7 | 8 | @Table("currency_rate") 9 | data class CurrencyRateModel( 10 | @Id val id: Long? = null, 11 | val base: String, 12 | val quote: String, 13 | val source: RateSource, 14 | val rate: BigDecimal 15 | ) -------------------------------------------------------------------------------- /market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/model/LastPrice.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.ports.postgres.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class LastPrice(val symbol:String, val matchedPrice: BigDecimal) -------------------------------------------------------------------------------- /market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/model/OpenOrderModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | import java.math.BigDecimal 6 | 7 | @Table("open_orders") 8 | data class OpenOrderModel( 9 | val ouid: String, 10 | val executedQuantity: BigDecimal?, 11 | val status: Int, 12 | @Id 13 | val id: Long? = null, 14 | ) -------------------------------------------------------------------------------- /market/market-ports/market-persister-postgres/src/main/kotlin/co/nilin/opex/market/ports/postgres/model/OrderStatusModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.market.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | import java.math.BigDecimal 6 | import java.time.LocalDateTime 7 | 8 | @Table("order_status") 9 | data class OrderStatusModel( 10 | val ouid: String, 11 | val executedQuantity: BigDecimal?, 12 | val accumulativeQuoteQty: BigDecimal?, 13 | val status: Int, 14 | val appearance: Int, 15 | val date: LocalDateTime = LocalDateTime.now(), 16 | @Id var id: Long? = null 17 | ) -------------------------------------------------------------------------------- /matching-engine/matching-engine-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 6 | -------------------------------------------------------------------------------- /matching-engine/matching-engine-app/src/main/kotlin/co/nilin/opex/matching/engine/app/MatchingEngineApp.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.app 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | import org.springframework.context.annotation.ComponentScan 6 | import org.springframework.scheduling.annotation.EnableScheduling 7 | 8 | @SpringBootApplication 9 | @ComponentScan("co.nilin.opex") 10 | @EnableScheduling 11 | class MatchingEngineApp 12 | 13 | fun main(args: Array) { 14 | runApplication(*args) 15 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-app/src/main/kotlin/co/nilin/opex/matching/engine/app/config/AppSchedulers.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.app.config 2 | 3 | import kotlinx.coroutines.asCoroutineDispatcher 4 | import java.util.concurrent.Executors 5 | 6 | object AppSchedulers { 7 | val generalExecutor = Executors.newFixedThreadPool(5).asCoroutineDispatcher() 8 | val kafkaExecutor = Executors.newSingleThreadExecutor().asCoroutineDispatcher() 9 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/eventh/events/CoreEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.eventh.events 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | import java.time.LocalDateTime 5 | 6 | open class CoreEvent( 7 | var pair: Pair, 8 | var eventDate: LocalDateTime = LocalDateTime.now() 9 | ) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/eventh/events/EditOrderRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.eventh.events 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | class EditOrderRequestEvent( 6 | var ouid: String = "", 7 | var uuid: String = "", 8 | var orderId: Long = 0, 9 | pair: Pair, 10 | var price: Long = 0, 11 | var quantity: Long = 0 12 | ) : CoreEvent(pair), OneOrderEvent { 13 | 14 | override fun ouid(): String { 15 | return ouid 16 | } 17 | 18 | override fun uuid(): String { 19 | return uuid 20 | } 21 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/eventh/events/OneOrderEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.eventh.events 2 | 3 | interface OneOrderEvent { 4 | fun ouid(): String 5 | fun uuid(): String 6 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/eventh/events/OrderBookPublishedEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.eventh.events 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | import co.nilin.opex.matching.engine.core.model.PersistentOrderBook 5 | 6 | data class OrderBookPublishedEvent(val persistentOrderBook: PersistentOrderBook) : CoreEvent(Pair()) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/inout/OrderCancelCommand.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | class OrderCancelCommand(val ouid: String, val uuid: String, val orderId: Long, val pair: Pair) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/inout/OrderCancelRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | class OrderCancelRequestEvent( 6 | ouid: String, 7 | uuid: String, 8 | pair: Pair, 9 | val orderId: Long 10 | ) : OrderRequestEvent(ouid, uuid, pair) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/inout/OrderCreateCommand.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.MatchConstraint 4 | import co.nilin.opex.matching.engine.core.model.OrderDirection 5 | import co.nilin.opex.matching.engine.core.model.OrderType 6 | import co.nilin.opex.matching.engine.core.model.Pair 7 | 8 | 9 | data class OrderCreateCommand( 10 | val ouid: String, 11 | val uuid: String, 12 | val pair: Pair, 13 | val price: Long, 14 | val quantity: Long, 15 | val direction: OrderDirection, 16 | val matchConstraint: MatchConstraint, 17 | val orderType: OrderType 18 | ) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/inout/OrderEditCommand.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | data class OrderEditCommand( 6 | val ouid: String, 7 | val uuid: String, 8 | val orderId: Long, 9 | val pair: Pair, 10 | val price: Long, 11 | val quantity: Long 12 | ) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/inout/OrderRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | abstract class OrderRequestEvent(val ouid:String, val uuid: String, val pair: Pair) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/inout/RejectReason.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.inout 2 | 3 | enum class RejectReason { 4 | ORDER_TYPE_NOT_MATCHED_MATCHC, ORDER_NOT_FOUND, OPERATION_NOT_MATCHED_MATCHC 5 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/inout/RequestedOperation.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.inout 2 | 3 | enum class RequestedOperation { 4 | PLACE_ORDER, CANCEL_ORDER, EDIT_ORDER 5 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/model/Bucket.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.model 2 | 3 | data class Bucket(val price: Long, var totalQuantity: Long, var ordersCount: Long, var lastOrder: SimpleOrder) -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/model/Order.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.model 2 | 3 | interface Order { 4 | fun id(): Long? 5 | fun persistent(): PersistentOrder 6 | } 7 | -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/model/Pair.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.model 2 | 3 | class Pair() { 4 | lateinit var leftSideName: String 5 | lateinit var rightSideName: String 6 | 7 | constructor(leftSideName: String, rightSideName: String) : this() { 8 | this.leftSideName = leftSideName 9 | this.rightSideName = rightSideName 10 | } 11 | 12 | override fun toString(): String { 13 | return "${leftSideName}_$rightSideName" 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/model/PersistentOrderBook.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.model 2 | 3 | class PersistentOrderBook { 4 | 5 | lateinit var pair: Pair 6 | var lastOrder: PersistentOrder? = null 7 | var orders: List? = emptyList() 8 | var tradeCounter: Long = 0 9 | 10 | constructor() { 11 | } 12 | 13 | constructor(pair: Pair) { 14 | this.pair = pair 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-core/src/main/kotlin/co/nilin/opex/matching/engine/core/spi/OrderBookPersister.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.core.spi 2 | 3 | import co.nilin.opex.matching.engine.core.model.PersistentOrderBook 4 | 5 | interface OrderBookPersister { 6 | suspend fun storeLastState(orderBook: PersistentOrderBook) 7 | suspend fun loadLastState(symbol: String): PersistentOrderBook? 8 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-ports/matching-engine-eventlistener-kafka/src/main/kotlin/co/nilin/opex/matching/engine/ports/kafka/listener/spi/EventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.matching.engine.core.eventh.events.CoreEvent 4 | 5 | interface EventListener { 6 | fun id(): String 7 | fun onEvent(event: CoreEvent, partition: Int, offset: Long, timestamp: Long) 8 | } -------------------------------------------------------------------------------- /matching-engine/matching-engine-ports/matching-engine-eventlistener-kafka/src/main/kotlin/co/nilin/opex/matching/engine/ports/kafka/listener/spi/OrderRequestEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.engine.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.matching.engine.core.inout.OrderRequestEvent 4 | 5 | interface OrderRequestEventListener { 6 | fun id(): String 7 | suspend fun onOrder(order: OrderRequestEvent, partition: Int, offset: Long, timestamp: Long) 8 | } -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 6 | -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/MatchingGatewayApp.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app 2 | 3 | import co.nilin.opex.utility.error.EnableOpexErrorHandler 4 | import org.springframework.boot.autoconfigure.SpringBootApplication 5 | import org.springframework.boot.runApplication 6 | import org.springframework.context.annotation.ComponentScan 7 | import org.springframework.scheduling.annotation.EnableScheduling 8 | 9 | @SpringBootApplication 10 | @ComponentScan("co.nilin.opex") 11 | @EnableOpexErrorHandler 12 | @EnableScheduling 13 | class MatchingGatewayApp 14 | 15 | fun main(args: Array) { 16 | runApplication(*args) 17 | } 18 | -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/config/AppConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.config 2 | 3 | import org.springframework.context.annotation.Configuration 4 | 5 | 6 | @Configuration 7 | class AppConfig -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/exception/NotAllowedToSubmitOrderException.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.exception 2 | 3 | class NotAllowedToSubmitOrderException : RuntimeException() { 4 | } -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/inout/BooleanResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.inout 2 | 3 | data class BooleanResponse(val result: Boolean) -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/inout/CancelOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.inout 2 | 3 | class CancelOrderRequest(val ouid: String, var uuid: String, val orderId: Long, val symbol: String) -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/inout/CreateOrderRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.MatchConstraint 4 | import co.nilin.opex.matching.engine.core.model.OrderDirection 5 | import co.nilin.opex.matching.engine.core.model.OrderType 6 | import java.math.BigDecimal 7 | 8 | data class CreateOrderRequest( 9 | var uuid: String?, 10 | val pair: String, 11 | val price: BigDecimal, 12 | val quantity: BigDecimal, 13 | val direction: OrderDirection, 14 | val matchConstraint: MatchConstraint, 15 | val orderType: OrderType, 16 | val userLevel: String 17 | ) -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/inout/PairConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | class PairConfig( 6 | val pair: String, 7 | val leftSideWalletSymbol: String, //can be same as pair left side 8 | val rightSideWalletSymbol: String, //can be same as pair right side 9 | val rightSideFraction: BigDecimal, 10 | val leftSideFraction: BigDecimal 11 | ) -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/inout/PairFeeConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class PairFeeConfig( 6 | val pairConfig: PairConfig, 7 | val direction: String?, 8 | val userLevel: String?, 9 | val makerFee: BigDecimal, 10 | val takerFee: BigDecimal 11 | ) 12 | -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/spi/AccountantApiProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.spi 2 | 3 | import co.nilin.opex.matching.engine.core.model.OrderDirection 4 | import co.nilin.opex.matching.gateway.app.inout.PairConfig 5 | import java.math.BigDecimal 6 | 7 | 8 | interface AccountantApiProxy { 9 | suspend fun canCreateOrder(uuid: String, symbol: String, value: BigDecimal): Boolean 10 | suspend fun fetchPairConfig(pair: String, direction: OrderDirection): PairConfig 11 | } -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-app/src/main/kotlin/co/nilin/opex/matching/gateway/app/spi/PairConfigLoader.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.app.spi 2 | 3 | import co.nilin.opex.matching.engine.core.model.OrderDirection 4 | import co.nilin.opex.matching.gateway.app.inout.PairConfig 5 | 6 | interface PairConfigLoader { 7 | suspend fun load(pair: String, direction: OrderDirection): PairConfig 8 | } -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-port/matching-gateway-submitter-kafka/src/main/kotlin/co/nilin/opex/matching/gateway/ports/kafka/submitter/inout/OrderCancelRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.ports.kafka.submitter.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | class OrderCancelRequestEvent( 6 | ouid: String, 7 | uuid: String, 8 | pair: Pair, 9 | val orderId: Long 10 | ) : OrderRequestEvent(ouid, uuid, pair) -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-port/matching-gateway-submitter-kafka/src/main/kotlin/co/nilin/opex/matching/gateway/ports/kafka/submitter/inout/OrderRequestEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.ports.kafka.submitter.inout 2 | 3 | import co.nilin.opex.matching.engine.core.model.Pair 4 | 5 | abstract class OrderRequestEvent(val ouid:String, val uuid: String, val pair: Pair) -------------------------------------------------------------------------------- /matching-gateway/matching-gateway-port/matching-gateway-submitter-kafka/src/main/kotlin/co/nilin/opex/matching/gateway/ports/kafka/submitter/inout/OrderSubmitResult.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.matching.gateway.ports.kafka.submitter.inout 2 | 3 | class OrderSubmitResult(offset: Long?) -------------------------------------------------------------------------------- /user-management/keycloak-gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | COPY target/classes/opex-master-realm.json opex-master-realm.json 5 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 6 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 7 | -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/ApplicationContextHolder.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway 2 | 3 | import org.springframework.context.ApplicationContext 4 | 5 | class ApplicationContextHolder { 6 | companion object { 7 | var applicationContext: ApplicationContext? = null 8 | 9 | fun getCurrentContext(): ApplicationContext? { 10 | return applicationContext 11 | } 12 | 13 | fun setCurrentContext(applicationContext: ApplicationContext) { 14 | Companion.applicationContext = applicationContext 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/config/KeycloakServerProperties.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @Configuration 7 | @ConfigurationProperties(prefix = "keycloak.server") 8 | class KeycloakServerProperties { 9 | var contextPath = "/auth" 10 | var realmImportFile = "/opex-realm.json" 11 | var adminUser = AdminUser() 12 | 13 | class AdminUser { 14 | var username = "admin" 15 | var password = "admin" 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/config/RegularJsonConfigProviderFactory.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.config 2 | 3 | import org.keycloak.services.util.JsonConfigProviderFactory 4 | 5 | class RegularJsonConfigProviderFactory : JsonConfigProviderFactory() { 6 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/ChangePasswordRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | class ChangePasswordRequest{ 4 | 5 | var password: String?=null 6 | var newPassword: String?=null 7 | var confirmation: String?=null 8 | 9 | constructor() 10 | 11 | constructor(password: String?, newPassword: String?, confirmation: String?) { 12 | this.password = password 13 | this.newPassword = newPassword 14 | this.confirmation = confirmation 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/ForgotPasswordRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | class ForgotPasswordRequest { 4 | 5 | var password: String? = null 6 | var passwordConfirmation: String? = null 7 | 8 | constructor() 9 | 10 | constructor(password: String?, passwordConfirmation: String?) { 11 | this.password = password 12 | this.passwordConfirmation = passwordConfirmation 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/Get2FAResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | data class Get2FAResponse(val uri: String, val secret: String, val qr: String) -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/KYCStatus.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | enum class KYCStatus { 4 | 5 | REQUESTED, ACCEPTED, REJECTED, NOT_REQUESTED, BLOCKED 6 | 7 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/KYCStatusResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | class KYCStatusResponse { 4 | 5 | var status: KYCStatus? = null 6 | var rejectReason: String? = null 7 | 8 | constructor() 9 | 10 | constructor(status: KYCStatus?, rejectReason: String?) { 11 | this.status = status 12 | this.rejectReason = rejectReason 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/KycRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | class KycRequest { 4 | 5 | var selfiePath: String? = null 6 | var idCardPath: String? = null 7 | var acceptFormPath: String? = null 8 | 9 | constructor() 10 | 11 | constructor(selfiePath: String?, idCardPath: String?, acceptFormPath: String?) { 12 | this.selfiePath = selfiePath 13 | this.idCardPath = idCardPath 14 | this.acceptFormPath = acceptFormPath 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/RegisterUserResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | class RegisterUserResponse { 4 | 5 | var id: String? = null 6 | 7 | constructor() 8 | 9 | constructor(id: String?) { 10 | this.id = id 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/Setup2FARequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | class Setup2FARequest { 4 | 5 | var secret: String? = null 6 | var initialCode: String? = null 7 | 8 | constructor() 9 | 10 | constructor(secret: String?, initialCode: String?) { 11 | this.secret = secret 12 | this.initialCode = initialCode 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/UploadResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | data class UploadResponse(val path: String) -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/UserSecurityCheckResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | data class UserSecurityCheckResponse( 4 | val otp: Boolean 5 | ) -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/UserSessionResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | data class UserSessionResponse( 4 | val id: String?, 5 | val ipAddress: String?, 6 | val started: Long, 7 | val lastAccess: Long, 8 | val state: String?, 9 | val agent: String?, 10 | val inUse: Boolean 11 | ) -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/WhiteListAdaptor.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | class WhiteListAdaptor { 4 | var data: MutableList?=null 5 | 6 | constructor() 7 | constructor(data: MutableList) { 8 | this.data = data 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/data/Whitelist.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.data 2 | 3 | data class Whitelist( 4 | val isEnabled: Boolean = false, 5 | val emails: List = emptyList() 6 | ) -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/model/ActionTokenResult.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.model 2 | 3 | enum class ActionTokenResult { 4 | 5 | SUCCEED, FAILED 6 | 7 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/model/AuthEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.model 2 | 3 | import java.time.LocalDateTime 4 | 5 | open class AuthEvent { 6 | var eventDate: LocalDateTime = LocalDateTime.now() 7 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/model/WhiteListModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.model 2 | 3 | 4 | import javax.persistence.* 5 | 6 | 7 | @Entity(name = "whitelist") 8 | @Table 9 | class WhiteListModel { 10 | @Id 11 | var id: String? = null 12 | var identifier: String? = null 13 | } 14 | -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/utils/Extensions.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.utils 2 | 3 | fun tryOrElse(alt: T?, body: () -> T?): T? { 4 | return try { 5 | body() 6 | } catch (e: Exception) { 7 | alt 8 | } 9 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/utils/VaultUserIdMechanism.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.gateway.utils 2 | 3 | import org.springframework.vault.authentication.AppIdUserIdMechanism 4 | 5 | class VaultUserIdMechanism() : AppIdUserIdMechanism { 6 | override fun createUserId(): String { 7 | return System.getenv("BACKEND_USER") 8 | } 9 | } -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.authenticator.CustomOTPAuthenticator 2 | co.nilin.opex.auth.gateway.authenticator.UserNotesAuthenticator -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.authentication.FormActionFactory: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.extension.RegistrationOpexCaptcha 2 | -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.common.util.ResteasyProvider: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.config.Resteasy3Provider -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.providers.CustomJpaEntityProviderFactory -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.email.EmailTemplateProviderFactory: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.providers.CustomEmailTemplateProviderFactory -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.extension.ExtendedEventListenerProviderFactory -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.platform.PlatformProvider: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.config.SimplePlatformProvider -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.providers.CustomOIDCProtocolMapper -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.extension.UserManagementResourceFactory 2 | co.nilin.opex.auth.gateway.extension.UserProfileResourceFactory 3 | -------------------------------------------------------------------------------- /user-management/keycloak-gateway/src/main/resources/META-INF/services/org.keycloak.vault.VaultProviderFactory: -------------------------------------------------------------------------------- 1 | co.nilin.opex.auth.gateway.extension.HashicorpVaultProviderFactory -------------------------------------------------------------------------------- /user-management/user-management-core/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /user-management/user-management-core/src/main/kotlin/co/nilin/opex/auth/core/data/KycLevel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.core.data 2 | 3 | enum class KycLevel { 4 | Level1, Level2, 5 | } 6 | 7 | -------------------------------------------------------------------------------- /user-management/user-management-core/src/main/kotlin/co/nilin/opex/auth/core/data/KycLevelUpdatedEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.core.data 2 | 3 | import java.time.LocalDateTime 4 | 5 | data class KycLevelUpdatedEvent(var userId:String, var kycLevel:KycLevel, var updateDate:LocalDateTime) 6 | -------------------------------------------------------------------------------- /user-management/user-management-core/src/main/kotlin/co/nilin/opex/auth/core/spi/KycLevelUpdatedEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.auth.core.spi 2 | 3 | import co.nilin.opex.auth.core.data.KycLevelUpdatedEvent 4 | 5 | 6 | interface KycLevelUpdatedEventListener { 7 | fun id(): String 8 | fun onEvent(event: KycLevelUpdatedEvent, partition: Int, offset: Long, timestamp: Long, eventId:String) 9 | 10 | } -------------------------------------------------------------------------------- /user-management/user-management-ports/user-management-kafka-listener/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /user-management/user-management-ports/user-management-kafka-listener/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /user-management/user-management-ports/user-management-kafka-listener/src/test/kotlin/co/nilin/opex/profile/ports/kafka/ProfilePostgressApplicationTests.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.profile.ports.kafka 2 | 3 | //@SpringBootTest 4 | //class ProfilePostgressApplicationTests { 5 | // 6 | // @Test 7 | // fun contextLoads() { 8 | // } 9 | // 10 | //} 11 | -------------------------------------------------------------------------------- /wallet/wallet-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11 2 | ARG JAR_FILE=target/*.jar 3 | COPY ${JAR_FILE} app.jar 4 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] 5 | HEALTHCHECK --interval=45s --start-period=30s --retries=5 CMD curl -sf 'http://localhost:8080/actuator/health' >/dev/null || exit 1 6 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/AppDispatchers.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.config 2 | 3 | import kotlinx.coroutines.asCoroutineDispatcher 4 | import java.util.concurrent.Executors 5 | 6 | object AppDispatchers { 7 | val kafkaExecutor = Executors.newSingleThreadExecutor().asCoroutineDispatcher() 8 | } -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/CurrencyRatesConfig.kt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opexdev/core/0889d8cfe651a90bf231e55cd5c1a324436ade95/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/CurrencyRatesConfig.kt -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/RestConfig.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.config 2 | 3 | import co.nilin.opex.utility.interceptors.FormDataWorkaroundFilter 4 | import org.springframework.context.annotation.Bean 5 | import org.springframework.context.annotation.Configuration 6 | import org.springframework.web.server.WebFilter 7 | 8 | @Configuration 9 | class RestConfig { 10 | @Bean 11 | fun formDataWebFilter(): WebFilter { 12 | return FormDataWorkaroundFilter() 13 | } 14 | } -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/AdminSearchWithdrawRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.wallet.core.model.WithdrawStatus 4 | 5 | data class AdminSearchWithdrawRequest( 6 | val uuid: String?, 7 | val currency: String?, 8 | val destTxRef: String?, 9 | val destAddress: String?, 10 | val status: List = emptyList(), 11 | ) 12 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/AdvanceReservedTransferData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | import java.util.* 5 | 6 | data class AdvanceReservedTransferData( 7 | val sourceSymbol: String, 8 | val destSymbol: String, 9 | val senderWalletType: String, 10 | val senderUuid: String, 11 | val receiverWalletType: String, 12 | val receiverUuid: String, 13 | val sourceAmount: BigDecimal, 14 | val reservedDestAmount: BigDecimal, 15 | val reserveTime: Date 16 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/CurrencyExchangeRatesResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | 6 | data class CurrencyExchangeRate( 7 | val sourceSymbol: String, 8 | val destSymbol: String, 9 | val rate: BigDecimal 10 | ) 11 | 12 | data class CurrencyExchangeRatesResponse(val rates: List) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/CurrencyPair.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.common.OpexError 4 | 5 | data class CurrencyPair( 6 | val sourceSymbol: String, 7 | val destSymbol: String 8 | ) { 9 | fun validate() { 10 | if (sourceSymbol == destSymbol) 11 | throw OpexError.SourceIsEqualDest.exception() 12 | } 13 | } -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/DepositHistoryRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | data class DepositHistoryRequest( 4 | val currency: String? = null, 5 | val startTime: Long? = null, 6 | val endTime: Long? = null, 7 | val limit: Int = 10, 8 | val offset: Int = 0, 9 | val ascendingByTime: Boolean = false 10 | ) 11 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/DepositResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.wallet.core.model.DepositStatus 4 | import co.nilin.opex.wallet.core.model.DepositType 5 | import java.math.BigDecimal 6 | import java.time.LocalDateTime 7 | import java.util.Date 8 | 9 | data class DepositResponse( 10 | val id: Long, 11 | val uuid: String, 12 | val currency: String, 13 | val amount: BigDecimal, 14 | val network: String?, 15 | val note: String?, 16 | val transactionRef: String?, 17 | val status: DepositStatus, 18 | val type: DepositType, 19 | val createDate: Date? 20 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/ManualTransferRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.util.UUID 4 | 5 | data class ManualTransferRequest( 6 | var description: String, 7 | var ref: String? = UUID.randomUUID().toString() 8 | ) 9 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/OwnerLimitsResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | data class OwnerLimitsResponse( 4 | val canTrade: Boolean, 5 | val canWithdraw: Boolean, 6 | val canDeposit: Boolean 7 | ) 8 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/PaymentCurrency.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | enum class PaymentCurrency { 4 | RIALS, TOMAN 5 | } -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/PaymentDepositRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class PaymentDepositRequest( 6 | val userId: String, // user uuid 7 | val amount: BigDecimal, 8 | val currency: PaymentCurrency, 9 | val reference: String, 10 | val description: String? 11 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/PaymentDepositResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | data class PaymentDepositResponse(val success: Boolean) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/RequestWithdrawBody.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class RequestWithdrawBody( 6 | val currency: String, 7 | val amount: BigDecimal, 8 | val destSymbol: String, 9 | val destAddress: String, 10 | val destNetwork: String, 11 | val destNote: String?, 12 | val description: String?, 13 | ) 14 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/SearchWithdrawRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.wallet.core.model.WithdrawStatus 4 | 5 | data class SearchWithdrawRequest( 6 | val currency: String?, 7 | val destTxRef: String?, 8 | val destAddress: String?, 9 | val status: List = emptyList() 10 | ) 11 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/SetCurrencyExchangeRateRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.common.OpexError 4 | import java.math.BigDecimal 5 | 6 | class SetCurrencyExchangeRateRequest( 7 | val sourceSymbol: String, 8 | val destSymbol: String, 9 | val rate: BigDecimal 10 | 11 | ) { 12 | 13 | fun validate() { 14 | if (rate <= BigDecimal.ZERO) 15 | throw OpexError.InvalidRate.exception() 16 | else if (sourceSymbol == destSymbol) 17 | throw OpexError.SourceIsEqualDest.exception() 18 | } 19 | } -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/TransactionRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.wallet.core.model.TransferCategory 4 | 5 | data class TransactionRequest( 6 | val coin: String?, 7 | val category: TransferCategory?, 8 | val startTime: Long? = null, 9 | val endTime: Long? = null, 10 | val limit: Int? = 10, 11 | val offset: Int? = 0, 12 | val ascendingByTime: Boolean = false 13 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/TransferPreEvaluateResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TransferPreEvaluateResponse( 6 | val destAmount: BigDecimal 7 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/TransferRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TransferRequest( 6 | val amount: BigDecimal, 7 | val symbol: String, 8 | val senderUuid: String, 9 | val senderWalletType: String, 10 | val receiverUuid: String, 11 | val receiverWalletType: String, 12 | val transferRef: String?, 13 | val description: String?, 14 | val transferCategory: String, 15 | val additionalData: Map? 16 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/TransferReserveRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.wallet.core.model.WalletType 4 | import java.math.BigDecimal 5 | 6 | data class TransferReserveRequest( 7 | val sourceAmount: BigDecimal, 8 | val sourceSymbol: String, 9 | val destSymbol: String, 10 | var senderUuid: String?, 11 | val senderWalletType: WalletType, 12 | val receiverUuid: String, 13 | val receiverWalletType: WalletType 14 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/TransferReserveResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TransferReserveResponse( 6 | val reserveUuid: String, 7 | val guaranteedDestAmount: BigDecimal 8 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserTransactionRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import co.nilin.opex.wallet.core.model.UserTransactionCategory 4 | 5 | data class UserTransactionRequest( 6 | val currency: String?, 7 | val category: UserTransactionCategory?, 8 | val startTime: Long? = null, 9 | val endTime: Long? = null, 10 | val limit: Int? = 10, 11 | val offset: Int? = 0, 12 | val ascendingByTime: Boolean = false 13 | ) -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/WalletData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | data class WalletData( 6 | val asset: String, 7 | var balance: BigDecimal, 8 | var locked: BigDecimal, 9 | var withdraw: BigDecimal 10 | ) 11 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/WithdrawHistoryRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.dto 2 | 3 | data class WithdrawHistoryRequest( 4 | val currency: String?, 5 | val startTime: Long? = null, 6 | val endTime: Long? = null, 7 | val limit: Int? = 10, 8 | val offset: Int? = 0, 9 | val ascendingByTime: Boolean = false 10 | ) 11 | -------------------------------------------------------------------------------- /wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/utils/VaultUserIdMechanism.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app.utils 2 | 3 | import org.springframework.vault.authentication.AppIdUserIdMechanism 4 | 5 | class VaultUserIdMechanism : AppIdUserIdMechanism { 6 | override fun createUserId(): String { 7 | return System.getenv("BACKEND_USER") 8 | } 9 | } -------------------------------------------------------------------------------- /wallet/wallet-app/src/test/kotlin/co/nilin/opex/wallet/app/WalletAppTest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.app 2 | 3 | import org.junit.jupiter.api.Test 4 | 5 | class WalletAppTest : KafkaEnabledTest() { 6 | 7 | @Test 8 | fun contextLoad() { 9 | } 10 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/exc/ConcurrentBalanceChangException.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.exc 2 | 3 | class ConcurrentBalanceChangException(override val message: String?): Exception() -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/exc/CurrencyNotMatchedException.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.exc 2 | 3 | class CurrencyNotMatchedException : Exception() -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/exc/DepositLimitExceededException.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.exc 2 | 3 | class DepositLimitExceededException : Exception() -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/exc/NotEnoughBalanceException.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.exc 2 | 3 | class NotEnoughBalanceException : Exception() -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/exc/WithdrawLimitExceededException.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.exc 2 | 3 | class WithdrawLimitExceededException : Exception() -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/FinancialActionResponseEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | data class FinancialActionResponseEvent( 4 | val uuid: String, 5 | var status: Status, 6 | var errorCode: Int? = null, 7 | var reason: String? = null 8 | ) 9 | 10 | enum class Status { PROCESSED, ERROR } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/TransferCommand.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | import co.nilin.opex.wallet.core.model.Amount 4 | import co.nilin.opex.wallet.core.model.TransferCategory 5 | import co.nilin.opex.wallet.core.model.Wallet 6 | 7 | data class TransferCommand( 8 | val sourceWallet: Wallet, 9 | val destWallet: Wallet, 10 | val amount: Amount, 11 | val description: String?, 12 | val transferRef: String?, 13 | val transferCategory: TransferCategory, 14 | val destAmount: Amount = amount 15 | ) 16 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/TransferResult.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | import co.nilin.opex.wallet.core.model.Amount 4 | import co.nilin.opex.wallet.core.model.WalletType 5 | 6 | data class TransferResult( 7 | val date: Long, 8 | val sourceUuid: String, 9 | val sourceWalletType: WalletType, 10 | val sourceBalanceBeforeAction: Amount, 11 | val sourceBalanceAfterAction: Amount, 12 | val amount: Amount, 13 | val destUuid: String, 14 | val destWalletType: WalletType, 15 | val receivedAmount: Amount 16 | ) 17 | 18 | data class TransferResultDetailed( 19 | val transferResult: TransferResult, 20 | val tx: String 21 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WalletData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | data class WalletData( 4 | val uuid: String, 5 | val title: String, 6 | val walletType: String, 7 | val currency: String, 8 | val balance: Double 9 | ) 10 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WalletTotal.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | data class WalletTotal( 4 | val currency: String, 5 | val balance: Double 6 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawAcceptCommand.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | class WithdrawAcceptCommand( 6 | val withdrawId: Long, 7 | val destAmount: BigDecimal?, 8 | val destTransactionRef: String, 9 | val destNote: String? 10 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawActionResult.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | import co.nilin.opex.wallet.core.model.WithdrawStatus 4 | 5 | class WithdrawActionResult(val withdrawId: Long, val status: WithdrawStatus) { 6 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawCommand.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | class WithdrawCommand( 6 | val uuid: String, 7 | val currency: String, 8 | val amount: BigDecimal, 9 | val description: String?, 10 | val destSymbol: String, 11 | val destAddress: String, 12 | val destNetwork: String, 13 | val destNote: String? 14 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawData.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | import java.math.BigDecimal 4 | 5 | data class WithdrawData( 6 | val isEnabled: Boolean, 7 | val fee: BigDecimal, 8 | val minimum: BigDecimal 9 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawRejectCommand.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.inout 2 | 3 | class WithdrawRejectCommand( 4 | val withdrawId: Long, 5 | val statusReason: String, 6 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/Amount.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class Amount(val currency: Currency, val amount: BigDecimal) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/BriefWallet.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class BriefWallet( 6 | val id: Long?, 7 | val ownerId: Long, 8 | val balance: BigDecimal, 9 | val currency: String, 10 | val type: WalletType 11 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/DepositStatus.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | enum class DepositStatus { 4 | 5 | PROCESSING, DONE 6 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/DepositType.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | enum class DepositType { 4 | 5 | ON_CHAIN, SYSTEM 6 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/TokenHolder.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | object TokenHolder { 4 | private val threadLocalToken = ThreadLocal() 5 | 6 | fun setToken(token: String) { 7 | threadLocalToken.set(token) 8 | } 9 | 10 | fun getToken(): String? { 11 | return threadLocalToken.get() 12 | } 13 | 14 | fun clearToken() { 15 | threadLocalToken.remove() 16 | } 17 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/Transaction.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | 6 | data class Transaction( 7 | val sourceWallet: Wallet, 8 | val destWallet: Wallet, 9 | val sourceAmount: BigDecimal, 10 | val destAmount: BigDecimal, 11 | val description: String?, 12 | val transferRef: String?, 13 | val transferCategory: TransferCategory, 14 | val transactionDate: LocalDateTime 15 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/TransactionHistory.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TransactionHistory( 6 | val id: Long, 7 | val currency: String, 8 | val wallet: String, 9 | val amount: BigDecimal, 10 | val description: String?, 11 | val ref: String?, 12 | val date: Long, 13 | val category: TransferCategory? 14 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/TransactionWithDetailHistory.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class TransactionWithDetailHistory( 6 | val id: Long, 7 | val srcWalletType: WalletType, 8 | val destWalletType: WalletType, 9 | val senderUuid: String, 10 | val receiverUuid: String, 11 | val currency: String, 12 | val amount: BigDecimal, 13 | val description: String?, 14 | val ref: String?, 15 | val date: Long, 16 | val category: TransferCategory, 17 | val withdraw: Boolean? = null 18 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/TransferCategory.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | enum class TransferCategory { 4 | 5 | NO_CATEGORY, 6 | DEPOSIT, 7 | DEPOSIT_MANUALLY, 8 | WITHDRAW_REQUEST, 9 | WITHDRAW_ACCEPT, 10 | WITHDRAW_REJECT, 11 | WITHDRAW_CANCEL, 12 | PURCHASE_FINALIZED, 13 | 14 | ORDER_CREATE, 15 | ORDER_CANCEL, 16 | ORDER_FINALIZED, 17 | TRADE, 18 | FEE, 19 | 20 | NORMAL //TODO TEST? 21 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/UserTransaction.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | import java.util.UUID 6 | 7 | data class UserTransaction( 8 | val ownerId: Long, 9 | val txId: Long, 10 | val currency: String, 11 | val balance: BigDecimal, 12 | val balanceChange: BigDecimal, 13 | val category: UserTransactionCategory, 14 | val description: String? = null, 15 | val uuid: String = UUID.randomUUID().toString(), 16 | val date: LocalDateTime = LocalDateTime.now() 17 | ) 18 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/UserTransactionCategory.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | enum class UserTransactionCategory { 4 | 5 | TRADE, 6 | DEPOSIT, 7 | DEPOSIT_TO, // for admin using DEPOSIT_MANUALLY 8 | WITHDRAW, 9 | FEE, 10 | SYSTEM 11 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/UserTransactionHistory.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | import java.math.BigDecimal 4 | import java.time.LocalDateTime 5 | 6 | data class UserTransactionHistory( 7 | val id: String, 8 | val userId: String, 9 | val currency: String, 10 | val balance: BigDecimal, 11 | val balanceChange: BigDecimal, 12 | val category: UserTransactionCategory, 13 | val description: String?, 14 | val date: LocalDateTime 15 | ) 16 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/Wallet.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | data class Wallet( 4 | val id: Long?, 5 | val owner: WalletOwner, 6 | val balance: Amount, 7 | val currency: Currency, 8 | val type: WalletType, 9 | val version: Long? 10 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/WalletLimitAction.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | enum class WalletLimitAction { 4 | 5 | DEPOSIT, WITHDRAW 6 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/WalletOwner.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | data class WalletOwner( 4 | val id: Long?, 5 | val uuid: String, 6 | val title: String, 7 | val level: String, 8 | val isTradeAllowed: Boolean, 9 | val isWithdrawAllowed: Boolean, 10 | val isDepositAllowed: Boolean 11 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/WalletType.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | enum class WalletType { 4 | 5 | MAIN, EXCHANGE, CASHOUT 6 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/WithdrawStatus.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model 2 | 3 | enum class WithdrawStatus { 4 | 5 | CREATED, 6 | PROCESSING, 7 | CANCELED, 8 | REJECTED, 9 | DONE 10 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/otc/ForbiddenPair.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model.otc 2 | 3 | data class ForbiddenPair ( 4 | val sourceSymbol: String, val destSymbol: String 5 | ) 6 | 7 | data class ForbiddenPairs ( 8 | var forbiddenPairs:List? 9 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/otc/LoginRequest.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model.otc 2 | 3 | data class LoginRequest(var clientId:String, var clientSecret:String) 4 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/otc/LoginResponse.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model.otc 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | 5 | data class LoginResponse(var data: Token) 6 | 7 | data class Token(@JsonProperty("access_token") 8 | val accessToken: String, 9 | @JsonProperty("expires_in") 10 | val expireIn: Long) 11 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/otc/Rate.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model.otc 2 | 3 | import java.math.BigDecimal 4 | 5 | data class Rate( 6 | val sourceSymbol: String, val destSymbol: String, val rate: BigDecimal 7 | ) 8 | 9 | data class Rates( 10 | var rates: List? 11 | ) -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/otc/Symbols.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.model.otc 2 | 3 | data class Symbols(var symbols:List?) 4 | 5 | 6 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/AuthProxy.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.spi 2 | 3 | import co.nilin.opex.wallet.core.model.CurrencyImp 4 | import co.nilin.opex.wallet.core.model.PropagateCurrencyChanges 5 | import co.nilin.opex.wallet.core.model.otc.* 6 | 7 | interface AuthProxy { 8 | suspend fun getToken(loginRequest: LoginRequest):LoginResponse 9 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/CurrencyRateService.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.spi 2 | 3 | import co.nilin.opex.wallet.core.model.Amount 4 | import co.nilin.opex.wallet.core.model.Currency 5 | import java.math.BigDecimal 6 | 7 | interface CurrencyRateService { 8 | suspend fun convert(amount: Amount, targetCurrency: Currency): BigDecimal 9 | } 10 | -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/FiActionResponseEventSubmitter.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.spi 2 | 3 | import co.nilin.opex.wallet.core.inout.FinancialActionResponseEvent 4 | 5 | interface FiActionResponseEventSubmitter { 6 | 7 | suspend fun submit(event: FinancialActionResponseEvent) 8 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/ReservedTransferManager.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.spi 2 | 3 | import co.nilin.opex.wallet.core.model.otc.ReservedTransfer 4 | 5 | interface ReservedTransferManager { 6 | 7 | suspend fun fetchValidReserve(reserveNumber:String): ReservedTransfer? 8 | 9 | suspend fun commitReserve(reserveNumber:String) 10 | 11 | suspend fun reserve(request: ReservedTransfer):ReservedTransfer 12 | 13 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/TransferManager.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.spi 2 | 3 | import co.nilin.opex.wallet.core.inout.TransferCommand 4 | import co.nilin.opex.wallet.core.inout.TransferResultDetailed 5 | 6 | interface TransferManager { 7 | 8 | suspend fun transfer(transferCommand: TransferCommand): TransferResultDetailed 9 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/WalletListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.spi 2 | 3 | import co.nilin.opex.wallet.core.model.Amount 4 | import co.nilin.opex.wallet.core.model.Wallet 5 | import java.math.BigDecimal 6 | 7 | interface WalletListener { 8 | 9 | suspend fun onDeposit( 10 | me: Wallet, 11 | sourceWallet: Wallet, 12 | amount: Amount, 13 | finalAmount: BigDecimal, 14 | transaction: String 15 | ) 16 | 17 | suspend fun onWithdraw( 18 | me: Wallet, 19 | destWallet: Wallet, 20 | amount: Amount, 21 | transaction: String 22 | ) 23 | } -------------------------------------------------------------------------------- /wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/WalletOwnerManager.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.core.spi 2 | 3 | import co.nilin.opex.wallet.core.model.Amount 4 | import co.nilin.opex.wallet.core.model.WalletOwner 5 | 6 | interface WalletOwnerManager { 7 | val systemUuid: String 8 | get() = "1" 9 | suspend fun isDepositAllowed(owner: WalletOwner, amount: Amount): Boolean 10 | suspend fun isWithdrawAllowed(owner: WalletOwner, amount: Amount): Boolean 11 | suspend fun findWalletOwner(uuid: String): WalletOwner? 12 | suspend fun createWalletOwner(uuid: String, title: String, userLevel: String): WalletOwner 13 | suspend fun findAllWalletOwners(): List 14 | } 15 | -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/model/AddCurrencyEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class AddCurrencyEvent( 6 | val name: String, 7 | val symbol: String, 8 | val precision: BigDecimal 9 | ) : AdminEvent() -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/model/AdminEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.model 2 | 3 | abstract class AdminEvent -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/model/AuthEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.model 2 | 3 | import java.time.LocalDateTime 4 | 5 | open class AuthEvent { 6 | var eventDate: LocalDateTime = LocalDateTime.now() 7 | } -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/model/DeleteCurrencyEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.model 2 | 3 | data class DeleteCurrencyEvent(val name: String) : AdminEvent() -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/model/EditCurrencyEvent.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.model 2 | 3 | import java.math.BigDecimal 4 | 5 | data class EditCurrencyEvent( 6 | val name: String, 7 | val symbol: String, 8 | val precision: BigDecimal 9 | ) : AdminEvent() -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/spi/AdminEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.wallet.ports.kafka.listener.model.AdminEvent 4 | 5 | interface AdminEventListener { 6 | 7 | fun id(): String 8 | 9 | fun onEvent(event: AdminEvent, partition: Int, offset: Long, timestamp: Long) 10 | 11 | } -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/spi/FinancialActionEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.wallet.ports.kafka.listener.model.FinancialActionEvent 4 | 5 | interface FinancialActionEventListener { 6 | 7 | fun id(): String 8 | 9 | fun onEvent(event: FinancialActionEvent, partition: Int, offset: Long, timestamp: Long) 10 | 11 | } -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-eventlistener-kafka/src/main/kotlin/co/nilin/opex/wallet/ports/kafka/listener/spi/UserCreatedEventListener.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.kafka.listener.spi 2 | 3 | import co.nilin.opex.wallet.ports.kafka.listener.model.UserCreatedEvent 4 | 5 | interface UserCreatedEventListener { 6 | fun id(): String 7 | fun onEvent(event: UserCreatedEvent, partition: Int, offset: Long, timestamp: Long) 8 | } -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/ReservedTransferRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.dao 2 | 3 | import co.nilin.opex.wallet.ports.postgres.model.ReservedTransferModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | import reactor.core.publisher.Mono 7 | 8 | @Repository 9 | interface ReservedTransferRepository : ReactiveCrudRepository { 10 | 11 | fun findByReserveNumber(reservedNumber:String): Mono? 12 | } -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/WalletConfigRepository.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.dao 2 | 3 | import co.nilin.opex.wallet.ports.postgres.model.WalletConfigModel 4 | import org.springframework.data.repository.reactive.ReactiveCrudRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface WalletConfigRepository : ReactiveCrudRepository -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/CurrencyDto.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.dto 2 | 3 | import co.nilin.opex.wallet.core.model.Currency 4 | import co.nilin.opex.wallet.ports.postgres.model.CurrencyModel 5 | 6 | fun CurrencyModel.toPlainObject() = Currency( 7 | symbol, 8 | name, 9 | precision 10 | ) 11 | 12 | fun Currency.toModel() = CurrencyModel( 13 | symbol, 14 | name, 15 | precision 16 | ) -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/DepositWithdrawTransaction.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.dto 2 | 3 | import co.nilin.opex.wallet.core.model.TransferCategory 4 | import java.math.BigDecimal 5 | import java.time.LocalDateTime 6 | 7 | data class DepositWithdrawTransaction( 8 | val id: Long, 9 | val wallet: String, 10 | val currency: String, 11 | val amount: BigDecimal, 12 | val description: String?, 13 | val ref: String?, 14 | val date: LocalDateTime, 15 | val category: TransferCategory 16 | ) -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/TransactionStat.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.dto 2 | 3 | import java.math.BigDecimal 4 | 5 | class TransactionStat( 6 | val cnt: Long?, 7 | val total: BigDecimal? 8 | ) -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/WalletOwnerDto.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.dto 2 | 3 | import co.nilin.opex.wallet.core.model.WalletOwner 4 | import co.nilin.opex.wallet.ports.postgres.model.WalletOwnerModel 5 | 6 | fun WalletOwnerModel.toPlainObject() = WalletOwner( 7 | id, 8 | uuid, 9 | title, 10 | level, 11 | isTradeAllowed, 12 | isWithdrawAllowed, 13 | isDepositAllowed 14 | ) 15 | 16 | fun WalletOwner.toModel() = WalletOwnerModel( 17 | id, 18 | uuid, 19 | title, 20 | level, 21 | isTradeAllowed, 22 | isWithdrawAllowed, 23 | isDepositAllowed 24 | ) -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/WalletStatExclusion.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.dto 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | 6 | @Table(name = "wallet_stat_exclusion") 7 | data class WalletStatExclusion( 8 | val walletId: Long, 9 | @Id 10 | val id: Long? = null 11 | ) -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/ForbiddenPairModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Column 5 | import org.springframework.data.relational.core.mapping.Table 6 | import java.time.LocalDateTime 7 | 8 | @Table("forbidden_pair") 9 | data class ForbiddenPairModel( 10 | @Id var id: Long?, 11 | var sourceSymbol: String, 12 | @Column("dest_symbol") 13 | var destinationSymbol: String, 14 | var lastUpdateDate: LocalDateTime = LocalDateTime.now(), 15 | var createDate: LocalDateTime 16 | ) -------------------------------------------------------------------------------- /wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/WalletConfigModel.kt: -------------------------------------------------------------------------------- 1 | package co.nilin.opex.wallet.ports.postgres.model 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Column 5 | import org.springframework.data.relational.core.mapping.Table 6 | 7 | @Table("wallet_config") 8 | data class WalletConfigModel(@Id val name: String, val mainCurrency: String) -------------------------------------------------------------------------------- /whitelist.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opexdev/core/0889d8cfe651a90bf231e55cd5c1a324436ade95/whitelist.txt --------------------------------------------------------------------------------