private async Task FinalizeSwap(IBitcoinTransaction transaction, IOffchainTransfer offchainTransfer) { var transactionsContextData = new Dictionary <string, SwapOffchainContextData>(); var allTransfers = new HashSet <string>(offchainTransfer.GetAdditionalData().ChildTransfers) { offchainTransfer.Id }; foreach (var transferId in allTransfers) { try { var transfer = await _offchainTransferRepository.GetTransfer(transferId); if (!transactionsContextData.ContainsKey(transfer.OrderId)) { var ctx = await _bitcoinTransactionService.GetTransactionContext <SwapOffchainContextData>(transaction.TransactionId); if (ctx == null) { continue; } transactionsContextData.Add(transfer.OrderId, ctx); } var contextData = transactionsContextData[transfer.OrderId]; var operation = contextData.Operations.FirstOrDefault(x => x.TransactionId == transferId); if (operation == null) { continue; } if (string.IsNullOrWhiteSpace(operation?.ClientTradeId) || string.IsNullOrWhiteSpace(operation?.ClientId)) { await _log.WriteWarningAsync(nameof(OffchainTransactionFinalizeFunction), nameof(FinalizeSwap), operation?.ToJson(), $"Missing fields. Client trade id {operation?.ClientTradeId}, client {operation?.ClientId}, transfer: {transferId}"); continue; } await Task.WhenAll( _offchainTransferRepository.CompleteTransfer(transferId), _clientTradesRepository.SetIsSettledAsync(operation.ClientId, operation.ClientTradeId, true) ); } catch (Exception e) { await _log.WriteErrorAsync(nameof(OffchainTransactionFinalizeFunction), nameof(FinalizeSwap), $"Transfer: {transferId}", e); } } }
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> 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); }
private async Task FinalizeCashOut(IBitcoinTransaction transaction, IOffchainTransfer offchainTransfer) { var amount = Math.Abs((double)offchainTransfer.Amount); var data = await _exchangeOperationsService.FinishCashOutAsync(transaction.TransactionId, offchainTransfer.ClientId, (double)offchainTransfer.Amount, offchainTransfer.AssetId); await CreateHubCashoutIfNeed(offchainTransfer); if (!data.IsOk()) { await _log.WriteWarningAsync("CashOutController", "CashOut", data.ToJson(), "ME operation failed"); await _srvSlackNotifications.SendNotification(ChannelTypes.Errors, $"Cashout failed in ME, client: {offchainTransfer.ClientId}, transfer: {transaction.TransactionId}, ME code result: {data.Code}"); } var contextData = await _bitcoinTransactionService.GetTransactionContext <CashOutContextData>(transaction.TransactionId); var swiftData = contextData.AddData?.SwiftData; if (swiftData != null) { await _cashOutAttemptRepository.SetIsSettledOffchain(contextData.ClientId, swiftData.CashOutRequestId); } else { if (offchainTransfer.AssetId == LykkeConstants.SolarAssetId) { await PostSolarCashOut(offchainTransfer.ClientId, contextData.Address, amount, transaction.TransactionId); } else if (offchainTransfer.AssetId == LykkeConstants.ChronoBankAssetId) { await PostChronoBankCashOut(contextData.Address, amount, transaction.TransactionId); } else if (offchainTransfer.AssetId == LykkeConstants.QuantaAssetId) { await PostQuantaCashOut(contextData.Address, amount, transaction.TransactionId); } else { var clientData = await _personalDataService.GetAsync(contextData.ClientId); await _srvEmailsFacade.SendNoRefundOCashOutMail(clientData.Email, contextData.Amount, contextData.AssetId, transaction.BlockchainHash); } } }
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 FinalizeTransfer(IBitcoinTransaction transaction, IOffchainTransfer transfer) { var contextData = await _bitcoinTransactionService.GetTransactionContext <TransferContextData>(transaction.TransactionId); switch (contextData.TransferType) { case TransferType.ToMarginAccount: await FinalizeTransferToMargin(contextData, transfer); return; case TransferType.Common: await FinalizeCommonTransfer(transaction, contextData); return; default: throw new ArgumentOutOfRangeException(); } }
private async Task FinalizeCommonTransfer(IBitcoinTransaction transaction, TransferContextData contextData) { foreach (var transfer in contextData.Transfers) { await _transferEventsRepository.SetIsSettledIfExistsAsync(transfer.ClientId, transfer.OperationId, true); var clientData = await _personalDataService.GetAsync(transfer.ClientId); if (transfer.Actions?.CashInConvertedOkEmail != null) { await _srvEmailsFacade.SendTransferCompletedEmail(clientData.Email, clientData.FullName, transfer.Actions.CashInConvertedOkEmail.AssetFromId, transfer.Actions.CashInConvertedOkEmail.AmountFrom, transfer.Actions.CashInConvertedOkEmail.AmountLkk, transfer.Actions.CashInConvertedOkEmail.Price, transaction.BlockchainHash); } if (transfer.Actions?.SendTransferEmail != null) { await _srvEmailsFacade.SendDirectTransferCompletedEmail(clientData.Email, clientData.FullName, transfer.Actions.SendTransferEmail.AssetId, transfer.Actions.SendTransferEmail.Amount, transaction.BlockchainHash); } if (transfer.Actions?.PushNotification != null) { var clientAcc = await _clientAccountsRepository.GetByIdAsync(transfer.ClientId); var asset = await _assetsService.TryGetAssetAsync(transfer.Actions.PushNotification.AssetId); await _appNotifications.SendAssetsCreditedNotification(new[] { clientAcc.NotificationsId }, transfer.Actions.PushNotification.Amount, transfer.Actions.PushNotification.AssetId, string.Format(TextResources.CreditedPushText, transfer.Actions.PushNotification.Amount.GetFixedAsString(asset.Accuracy), transfer.Actions.PushNotification.AssetId)); } } await _paymentTransactionsRepository.SetStatus(transaction.TransactionId, PaymentStatus.NotifyProcessed); }
private static TransactionStates GetState(IBitcoinTransaction transaction, bool isBtcOffchainClient) { return(isBtcOffchainClient ? (string.IsNullOrWhiteSpace(transaction.BlockchainHash) ? TransactionStates.SettledOffchain : TransactionStates.SettledOnchain) : (string.IsNullOrWhiteSpace(transaction.BlockchainHash) ? TransactionStates.InProcessOnchain : TransactionStates.SettledOnchain)); }
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); }
public static BaseContextData GetBaseContextData(this IBitcoinTransaction src) { return(Newtonsoft.Json.JsonConvert.DeserializeObject <BaseContextData>(src.ContextData)); }
public static T GetContextData <T>(this IBitcoinTransaction src) { return(Newtonsoft.Json.JsonConvert.DeserializeObject <T>(src.ContextData)); }
private async Task FinalizeIssue(IBitcoinTransaction transaction) { var contextData = await _bitcoinTransactionService.GetTransactionContext <IssueContextData>(transaction.TransactionId); await _cashOperationsRepository.SetIsSettledAsync(contextData.ClientId, contextData.CashOperationId, true); }