private async Task ProcessCashOut(CashInOutQueueMessage message)
        {
            var walletCredentials = await _walletCredentialsRepository.GetAsync(message.ClientId);

            var amount        = message.Amount.ParseAnyDecimal();
            var transactionId = message.Id;
            var context       = await _transactionService.GetTransactionContext <CashOutContextData>(transactionId);

            context.CashOperationId = transactionId;

            _cqrsEngine.SendCommand(new SaveCashoutOperationStateCommand
            {
                Command = new CashOutCommand
                {
                    Amount             = Math.Abs(amount),
                    AssetId            = message.AssetId,
                    Context            = context.ToJson(),
                    SourceAddress      = walletCredentials?.MultiSig,
                    DestinationAddress = context.Address,
                    TransactionId      = Guid.Parse(transactionId)
                },
                Context = context,
                Message = message
            }, BoundedContexts.TxHandler, BoundedContexts.Operations);
        }
 private void ProcessManualUpdate(CashInOutQueueMessage message)
 {
     _cqrsEngine.SendCommand(new SaveManualOperationStateCommand
     {
         Message = message
     }, BoundedContexts.TxHandler, BoundedContexts.Operations);
 }
        private async Task ProcessIssue(CashInOutQueueMessage message)
        {
            var isClientTrusted = await _clientAccountClient.IsTrustedAsync(message.ClientId);

            var asset = await _assetsServiceWithCache.TryGetAssetAsync(message.AssetId);

            if (!isClientTrusted.Value && !asset.IsTrusted)
            {
                _log.Warning($"{nameof(CashInOutMessageProcessor)}:{nameof(ProcessIssue)}", "Client and asset are not trusted.", context: message.ToJson());
                return;
            }

            var walletCredentials = await _walletCredentialsRepository.GetAsync(message.ClientId);

            var amount        = message.Amount.ParseAnyDecimal();
            var transactionId = message.Id;
            var context       = await _transactionService.GetTransactionContext <IssueContextData>(transactionId);

            context.CashOperationId = transactionId;
            _cqrsEngine.SendCommand(new SaveIssueOperationStateCommand
            {
                Command = new IssueCommand
                {
                    TransactionId = Guid.Parse(transactionId),
                    Context       = context.ToJson(),
                    Amount        = Math.Abs(amount),
                    AssetId       = message.AssetId,
                    Multisig      = walletCredentials?.MultiSig
                },
                Context = context,
                Message = message
            }, BoundedContexts.TxHandler, BoundedContexts.Operations);
        }
        private async Task ProcessExternalCashin(CashInOutQueueMessage message)
        {
            var asset = await _assetsServiceWithCache.TryGetAssetAsync(message.AssetId);

            if (asset.Blockchain != Blockchain.Bitcoin || asset.IsTrusted && asset.Id != LykkeConstants.BitcoinAssetId)
            {
                return;
            }

            if (asset.Id == LykkeConstants.BitcoinAssetId)
            {
                var cashinType = await _bitcoinCashinTypeRepository.GetAsync(message.Id);

                if (cashinType == null || !cashinType.IsSegwit)
                {
                    _cqrsEngine.SendCommand(new CreateOffchainCashoutRequestCommand
                    {
                        Id       = message.Id,
                        ClientId = message.ClientId,
                        AssetId  = message.AssetId,
                        Amount   = (decimal)message.Amount.ParseAnyDouble()
                    }, BoundedContexts.TxHandler, BoundedContexts.Offchain);
                }
                else
                {
                    _cqrsEngine.SendCommand(new SegwitTransferCommand
                    {
                        Id      = message.Id,
                        Address = cashinType.Address
                    }, BoundedContexts.TxHandler, BoundedContexts.Bitcoin);
                }
            }
        }
        private async Task <bool> ProcessIssue(IBitcoinTransaction transaction, CashInOutQueueMessage msg)
        {
            var isOffchain = await _clientSettingsRepository.IsOffchainClient(msg.ClientId);

            //Get client wallet
            var walletCredentials = await _walletCredentialsRepository
                                    .GetAsync(msg.ClientId);

            var amount  = msg.Amount.ParseAnyDouble();
            var context = await _bitcoinTransactionService.GetTransactionContext <IssueContextData>(transaction.TransactionId);

            //Register cash operation
            var cashOperationId = await _cashOperationsRepository
                                  .RegisterAsync(new CashInOutOperation
            {
                Id            = Guid.NewGuid().ToString("N"),
                ClientId      = msg.ClientId,
                Multisig      = walletCredentials.MultiSig,
                AssetId       = msg.AssetId,
                Amount        = Math.Abs(amount),
                DateTime      = DateTime.UtcNow,
                AddressTo     = walletCredentials.MultiSig,
                TransactionId = transaction.TransactionId,
                State         = isOffchain ? TransactionStates.InProcessOffchain : TransactionStates.InProcessOnchain
            });

            context.CashOperationId = cashOperationId;
            var contextJson = context.ToJson();
            var cmd         = new IssueCommand
            {
                Amount        = amount,
                AssetId       = msg.AssetId,
                Multisig      = walletCredentials.MultiSig,
                Context       = contextJson,
                TransactionId = Guid.Parse(transaction.TransactionId)
            };

            await _bitcoinTransactionsRepository.UpdateAsync(transaction.TransactionId, cmd.ToJson(), null, "");

            await _bitcoinTransactionService.SetTransactionContext(transaction.TransactionId, context);

            if (isOffchain)
            {
                await _offchainRequestService.CreateOffchainRequestAndNotify(transaction.TransactionId, msg.ClientId, msg.AssetId, (decimal)amount, null, OffchainTransferType.CashinToClient);
            }
            else
            {
                await _bitcoinCommandSender.SendCommand(cmd);
            }

            return(true);
        }
        private async Task <bool> ProcessExternalCashin(CashInOutQueueMessage msg)
        {
            var asset = await _assetsService.TryGetAssetAsync(msg.AssetId);

            if (!await _clientSettingsRepository.IsOffchainClient(msg.ClientId) || asset.Blockchain != Blockchain.Bitcoin)
            {
                return(true);
            }

            var amount = msg.Amount.ParseAnyDouble();
            await _offchainRequestService.CreateOffchainRequestAndNotify(Guid.NewGuid().ToString(), msg.ClientId, msg.AssetId, (decimal)amount, null, OffchainTransferType.CashinFromClient);

            return(true);
        }
        public async Task <bool> ProcessMessage(CashInOutQueueMessage queueMessage)
        {
            var transaction = await _bitcoinTransactionsRepository.FindByTransactionIdAsync(queueMessage.Id);

            if (transaction == null)
            {
                // external cashin
                if (_cashOperationsRepository.GetAsync(queueMessage.ClientId, queueMessage.Id) != null)
                {
                    return(await ProcessExternalCashin(queueMessage));
                }

                await _log.WriteWarningAsync(nameof(CashInOutQueue), nameof(ProcessMessage), queueMessage.ToJson(), "unkown transaction");

                return(false);
            }

            try
            {
                switch (transaction.CommandType)
                {
                case BitCoinCommands.Issue:
                    return(await ProcessIssue(transaction, queueMessage));

                case BitCoinCommands.CashOut:
                    return(await ProcessCashOut(transaction, queueMessage));

                case BitCoinCommands.Destroy:
                    return(await ProcessDestroy(transaction, queueMessage));

                case BitCoinCommands.ManualUpdate:
                    return(await ProcessManualOperation(transaction, queueMessage));

                default:
                    await _log.WriteWarningAsync(nameof(CashInOutQueue), nameof(ProcessMessage), queueMessage.ToJson(), $"Unknown command type (value = [{transaction.CommandType}])");

                    return(false);
                }
            }
            catch (Exception ex)
            {
                await _log.WriteErrorAsync(nameof(CashInOutQueue), nameof(ProcessMessage), queueMessage.ToJson(), ex);

                return(false);
            }
        }
        public async Task ProcessMessage(CashInOutQueueMessage message)
        {
            _log.Info(message: "Processing message", message.ToJson());

            ChaosKitty.Meow();

            var transaction = await _transactionsRepository.FindByTransactionIdAsync(message.Id);

            if (transaction == null)
            {
                if (_cashOperationsRepositoryClient.GetAsync(message.ClientId, message.Id) == null)
                {
                    _log.Warning($"{nameof(CashInOutQueue)}:{nameof(CashInOutQueueMessage)}", "unknown transaction", context: message.ToJson());
                    return;
                }

                await ProcessExternalCashin(message);
            }
            else
            {
                switch (transaction.CommandType)
                {
                case BitCoinCommands.CashIn:
                case BitCoinCommands.Issue:
                    await ProcessIssue(message);

                    break;

                case BitCoinCommands.CashOut:
                    await ProcessCashOut(message);

                    break;

                case BitCoinCommands.ManualUpdate:
                    ProcessManualUpdate(message);
                    break;

                default:
                    _log.Warning($"{nameof(CashInOutQueue)}:{nameof(CashInOutQueueMessage)}", $"Unknown command type (value = [{transaction.CommandType}])", context: message.ToJson());
                    break;
                }
            }
        }
        private async Task <bool> ProcessDestroy(IBitcoinTransaction transaction, CashInOutQueueMessage msg)
        {
            var amount = msg.Amount.ParseAnyDouble();
            //Get uncolor context data
            var context = await _bitcoinTransactionService.GetTransactionContext <UncolorContextData>(transaction.TransactionId);

            //Register cash operation
            var cashOperationId = await _cashOperationsRepository
                                  .RegisterAsync(new CashInOutOperation
            {
                Id            = Guid.NewGuid().ToString("N"),
                ClientId      = msg.ClientId,
                Multisig      = context.AddressFrom,
                AssetId       = msg.AssetId,
                Amount        = -Math.Abs(amount),
                DateTime      = DateTime.UtcNow,
                AddressFrom   = context.AddressFrom,
                AddressTo     = context.AddressTo,
                TransactionId = msg.Id
            });

            //Update context data
            context.CashOperationId = cashOperationId;
            var contextJson = context.ToJson();
            var cmd         = new DestroyCommand
            {
                Context       = contextJson,
                Amount        = Math.Abs(amount),
                AssetId       = msg.AssetId,
                Address       = context.AddressFrom,
                TransactionId = Guid.Parse(msg.Id)
            };

            await _bitcoinTransactionsRepository.UpdateAsync(transaction.TransactionId, cmd.ToJson(), null, "");

            await _bitcoinTransactionService.SetTransactionContext(transaction.TransactionId, context);

            //Send to bitcoin
            await _bitcoinCommandSender.SendCommand(cmd);

            return(true);
        }
Ejemplo n.º 10
0
 private async Task ProcessMessage(CashInOutQueueMessage queueMessage)
 {
     await _delayWampUpSubject.OnNewOperation(queueMessage.ClientId);
 }
        private async Task <bool> ProcessCashOut(IBitcoinTransaction transaction, CashInOutQueueMessage msg)
        {
            //Get client wallet
            var walletCredentials = await _walletCredentialsRepository
                                    .GetAsync(msg.ClientId);

            var amount  = msg.Amount.ParseAnyDouble();
            var context = await _bitcoinTransactionService.GetTransactionContext <CashOutContextData>(transaction.TransactionId);

            var asset = await _assetsService.TryGetAssetAsync(msg.AssetId);

            var isOffchainClient = await _clientSettingsRepository.IsOffchainClient(msg.ClientId);

            var isBtcOffchainClient = isOffchainClient && asset.Blockchain == Blockchain.Bitcoin;

            bool isForwardWithdawal = context.AddData?.ForwardWithdrawal != null;

            if (isForwardWithdawal)
            {
                var baseAsset = await _assetsService.TryGetAssetAsync(asset.ForwardBaseAsset);

                var forwardCashInId = await _cashOperationsRepository
                                      .RegisterAsync(new CashInOutOperation
                {
                    Id            = Guid.NewGuid().ToString(),
                    ClientId      = msg.ClientId,
                    Multisig      = walletCredentials.MultiSig,
                    AssetId       = baseAsset.Id,
                    Amount        = Math.Abs(amount),
                    DateTime      = DateTime.UtcNow.AddDays(asset.ForwardFrozenDays),
                    AddressFrom   = walletCredentials.MultiSig,
                    AddressTo     = context.Address,
                    TransactionId = msg.Id,
                    Type          = CashOperationType.ForwardCashIn,
                    State         = isBtcOffchainClient ?
                                    TransactionStates.InProcessOffchain : TransactionStates.InProcessOnchain
                });

                await _forwardWithdrawalRepository.SetLinkedCashInOperationId(msg.ClientId, context.AddData.ForwardWithdrawal.Id,
                                                                              forwardCashInId);
            }

            //Register cash operation
            var cashOperationId = await _cashOperationsRepository
                                  .RegisterAsync(new CashInOutOperation
            {
                Id             = Guid.NewGuid().ToString(),
                ClientId       = msg.ClientId,
                Multisig       = walletCredentials.MultiSig,
                AssetId        = msg.AssetId,
                Amount         = -Math.Abs(amount),
                DateTime       = DateTime.UtcNow,
                AddressFrom    = walletCredentials.MultiSig,
                AddressTo      = context.Address,
                TransactionId  = msg.Id,
                Type           = isForwardWithdawal ? CashOperationType.ForwardCashOut : CashOperationType.None,
                BlockChainHash = asset.IssueAllowed && isBtcOffchainClient ? string.Empty : transaction.BlockchainHash,
                State          = GetState(transaction, isBtcOffchainClient)
            });

            //Update context data
            context.CashOperationId = cashOperationId;
            var contextJson = context.ToJson();
            var cmd         = new CashOutCommand
            {
                Amount             = Math.Abs(amount),
                AssetId            = msg.AssetId,
                Context            = contextJson,
                SourceAddress      = walletCredentials.MultiSig,
                DestinationAddress = context.Address,
                TransactionId      = Guid.Parse(transaction.TransactionId)
            };

            await _bitcoinTransactionsRepository.UpdateAsync(transaction.TransactionId, cmd.ToJson(), null, "");

            await _bitcoinTransactionService.SetTransactionContext(transaction.TransactionId, context);

            if (!isOffchainClient && asset.Blockchain == Blockchain.Bitcoin)
            {
                await _bitcoinCommandSender.SendCommand(cmd);
            }

            if (asset.Blockchain == Blockchain.Ethereum)
            {
                string errMsg = string.Empty;

                try
                {
                    var address = await _bcnClientCredentialsRepository.GetClientAddress(msg.ClientId);

                    var txRequest =
                        await _ethereumTransactionRequestRepository.GetAsync(Guid.Parse(transaction.TransactionId));

                    txRequest.OperationIds = new[] { cashOperationId };
                    await _ethereumTransactionRequestRepository.UpdateAsync(txRequest);

                    var response = await _srvEthereumHelper.SendCashOutAsync(txRequest.Id,
                                                                             txRequest.SignedTransfer.Sign,
                                                                             asset, address, txRequest.AddressTo,
                                                                             txRequest.Volume);

                    if (response.HasError)
                    {
                        errMsg = response.Error.ToJson();
                    }
                }
                catch (Exception e)
                {
                    errMsg = $"{e.GetType()}\n{e.Message}";
                }

                if (!string.IsNullOrEmpty(errMsg))
                {
                    await _ethClientEventLogs.WriteEvent(msg.ClientId, Event.Error,
                                                         new { Request = transaction.TransactionId, Error = errMsg }.ToJson());
                }
            }

            return(true);
        }
        private async Task <bool> ProcessManualOperation(IBitcoinTransaction transaction, CashInOutQueueMessage msg)
        {
            var asset = await _assetsService.TryGetAssetAsync(msg.AssetId);

            var walletCredentials = await _walletCredentialsRepository.GetAsync(msg.ClientId);

            var context          = transaction.GetContextData <CashOutContextData>();
            var isOffchainClient = await _clientSettingsRepository.IsOffchainClient(msg.ClientId);

            var isBtcOffchainClient = isOffchainClient && asset.Blockchain == Blockchain.Bitcoin;

            var operation = new CashInOutOperation
            {
                Id             = Guid.NewGuid().ToString(),
                ClientId       = msg.ClientId,
                Multisig       = walletCredentials.MultiSig,
                AssetId        = msg.AssetId,
                Amount         = msg.Amount.ParseAnyDouble(),
                DateTime       = DateTime.UtcNow,
                AddressFrom    = walletCredentials.MultiSig,
                AddressTo      = context.Address,
                TransactionId  = msg.Id,
                Type           = CashOperationType.None,
                BlockChainHash = asset.IssueAllowed && isBtcOffchainClient ? string.Empty : transaction.BlockchainHash,
                State          = GetState(transaction, isBtcOffchainClient)
            };

            var newHistoryEntry = new HistoryEntry
            {
                ClientId   = operation.ClientId,
                Amount     = operation.Amount,
                Currency   = asset.Name,
                DateTime   = msg.Date,
                OpType     = "CashInOut",
                CustomData = JsonConvert.SerializeObject(operation)
            };

            try
            {
                await _cashOperationsRepository.RegisterAsync(operation)
                .ContinueWith(t => _historyWriter.Push(newHistoryEntry));
            }
            catch (Exception e)
            {
                await _log.WriteErrorAsync(nameof(CashInOutQueue), nameof(ProcessManualOperation), null, e);

                return(false);
            }

            return(true);
        }
Ejemplo n.º 13
0
 public static void AddFeeDataToOperation(this CashInOutOperation operation, CashInOutQueueMessage message)
 {
     operation.FeeSize = (double)(message?.Fees?.FirstOrDefault()?.Transfer?.Volume ?? 0);
     operation.FeeType = FeeType.Absolute;
 }