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); }
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); }
public static void AddFeeDataToOperation(this CashInOutOperation operation, CashInOutQueueMessage message) { operation.FeeSize = (double)(message?.Fees?.FirstOrDefault()?.Transfer?.Volume ?? 0); operation.FeeType = FeeType.Absolute; }