Exemple #1
0
        public async Task <bool> ProcessMessage(TradeQueueItem queueMessage)
        {
            await _marketOrdersRepository.CreateAsync(queueMessage.Order);

            if (!queueMessage.Order.Status.Equals("matched", StringComparison.OrdinalIgnoreCase))
            {
                await _log.WriteInfoAsync(nameof(TradeQueue), nameof(ProcessMessage), queueMessage.Order.ToJson(), "Message processing being aborted, due to order status is not matched. Order was saved");

                return(true);
            }

            var walletCredsMarket = await _walletCredentialsRepository.GetAsync(queueMessage.Trades[0].MarketClientId);

            var walletCredsLimit = await _walletCredentialsRepository.GetAsync(queueMessage.Trades[0].LimitClientId);

            var clientTrades = queueMessage.ToDomainOffchain(walletCredsMarket, walletCredsLimit, await _assetsService.GetAllAssetsAsync());

            var notify = new HashSet <string>();

            try
            {
                // for trusted clients only write history (finally block)
                if (await _clientAccountsRepository.IsTrusted(queueMessage.Order.ClientId))
                {
                    return(true);
                }

                // get operations only by market order user (limit user will be processed in limit trade queue)
                var operations = AggregateSwaps(queueMessage.Trades).Where(x => x.ClientId == queueMessage.Order.ClientId).ToList();

                await CreateTransaction(queueMessage.Order.ExternalId, operations, clientTrades);

                var ethereumTxRequest = await _ethereumTransactionRequestRepository.GetByOrderAsync(queueMessage.Order.ExternalId);

                if (ethereumTxRequest != null)
                {
                    var wasTransferOk = await ProcessEthGuaranteeTransfer(ethereumTxRequest, operations, clientTrades);

                    if (!wasTransferOk)
                    {
                        return(true);
                    }
                }

                var sellOperations = operations.Where(x => x.Amount < 0);
                var buyOperations  = operations.Where(x => x.Amount > 0);

                foreach (var operation in sellOperations)
                {
                    var asset = await _assetsService.TryGetAssetAsync(operation.AssetId);

                    if (asset.Blockchain == Blockchain.Ethereum)
                    {
                        continue;   //guarantee transfer already sent for eth
                    }
                    // return change in offchain
                    var offchainOrder = await _offchainOrdersRepository.GetOrder(queueMessage.Order.ExternalId);

                    var change = offchainOrder.ReservedVolume - Math.Abs(operation.Amount);

                    if (change < 0)
                    {
                        await _log.WriteWarningAsync(nameof(TradeQueue), nameof(ProcessMessage),
                                                     $"Order: [{offchainOrder.OrderId}], data: [{operation.ToJson()}]",
                                                     "Diff is less than ZERO !");
                    }

                    if (change > 0)
                    {
                        await _offchainRequestService.CreateOffchainRequestAndNotify(operation.TransferId, operation.ClientId,
                                                                                     operation.AssetId, change, offchainOrder.OrderId, OffchainTransferType.FromHub);

                        notify.Add(operation.ClientId);
                    }
                }

                foreach (var operation in buyOperations)
                {
                    var asset = await _assetsService.TryGetAssetAsync(operation.AssetId);

                    if (asset.Blockchain == Blockchain.Ethereum)
                    {
                        await ProcessEthBuy(operation, asset, clientTrades, queueMessage.Order.ExternalId);

                        continue;
                    }

                    await _offchainRequestService.CreateOffchainRequestAndNotify(operation.TransferId, operation.ClientId,
                                                                                 operation.AssetId, operation.Amount, queueMessage.Order.ExternalId, OffchainTransferType.FromHub);

                    notify.Add(operation.ClientId);
                }
            }
            finally
            {
                await _clientTradesRepository.SaveAsync(clientTrades);

                foreach (var item in notify)
                {
                    await _offchainRequestService.NotifyUser(item);
                }
            }

            return(true);
        }
        private async Task ReturnRemainingVolume(LimitQueueItem.LimitOrderWithTrades limitOrderWithTrades)
        {
            var order         = limitOrderWithTrades.Order;
            var offchainOrder = await _offchainOrdersRepository.GetOrder(order.Id);

            var type      = order.Volume > 0 ? OrderType.Buy : OrderType.Sell;
            var assetPair = await _assetsService.TryGetAssetPairAsync(order.AssetPairId);

            var neededAsset = type == OrderType.Buy ? assetPair.QuotingAssetId : assetPair.BaseAssetId;
            var asset       = await _assetsService.TryGetAssetAsync(neededAsset);

            if (type == OrderType.Buy)
            {
                var initial = offchainOrder.ReservedVolume;

                var trades = await _clientTradesRepository.GetByOrderAsync(order.Id);

                var executed = trades.Where(x => x.AssetId == neededAsset && x.ClientId == order.ClientId)
                               .Select(x => x.Amount).DefaultIfEmpty(0).Sum();

                var returnAmount = Math.Max(0, initial - Math.Abs((decimal)executed));

                if (asset.Blockchain == Blockchain.Ethereum)
                {
                    // if order partially or fully executed then broadcast guarantee transfer
                    if (offchainOrder.Volume > returnAmount)
                    {
                        await ProcessEthGuaranteeTransfer(order.Id, returnAmount);
                    }
                    return;
                }

                if (returnAmount > 0)
                {
                    await _offchainRequestService.CreateOffchainRequestAndUnlock(Guid.NewGuid().ToString(),
                                                                                 order.ClientId,
                                                                                 neededAsset, returnAmount, order.Id, OffchainTransferType.FromHub);
                }
            }
            else
            {
                var remainigVolume = Math.Abs((decimal)order.RemainingVolume);

                if (asset.Blockchain == Blockchain.Ethereum)
                {
                    var initialVolume = Math.Abs(offchainOrder.Volume);
                    // if order partially or fully executed then broadcast guarantee transfer
                    // if initialVolume == remainigVolume then user cancelled limit order without partial executing
                    if (initialVolume > remainigVolume)
                    {
                        await ProcessEthGuaranteeTransfer(order.Id, remainigVolume);
                    }
                    return;
                }

                if (remainigVolume > 0)
                {
                    await _offchainRequestService.CreateOffchainRequestAndUnlock(Guid.NewGuid().ToString(), order.ClientId,
                                                                                 neededAsset, remainigVolume, order.Id, OffchainTransferType.FromHub);
                }
            }
        }