private async Task ProcessEthBuy(AggregatedTransfer operation, IAsset asset, IClientTrade[] clientTrades, string orderId) { string errMsg = string.Empty; var transferId = Guid.NewGuid(); try { var toAddress = await _bcnClientCredentialsRepository.GetClientAddress(operation.ClientId); await _ethereumTransactionRequestRepository.InsertAsync(new EthereumTransactionRequest { AddressTo = toAddress, AssetId = asset.Id, ClientId = operation.ClientId, Id = transferId, OperationIds = clientTrades.Where(x => x.ClientId == operation.ClientId && x.Amount > 0) .Select(x => x.Id) .ToArray(), OperationType = OperationType.Trade, OrderId = orderId, Volume = operation.Amount }); var res = await _srvEthereumHelper.SendTransferAsync(transferId, string.Empty, asset, _settings.HotwalletAddress, toAddress, operation.Amount); if (res.HasError) { errMsg = res.Error.ToJson(); await _log.WriteWarningAsync(nameof(TradeQueue), nameof(ProcessEthGuaranteeTransfer), errMsg, string.Empty); } } catch (Exception e) { await _log.WriteErrorAsync(nameof(TradeQueue), nameof(ProcessEthGuaranteeTransfer), e.Message, e); errMsg = $"{e.GetType()}\n{e.Message}"; } if (!string.IsNullOrEmpty(errMsg)) { await _ethClientEventLogs.WriteEvent(operation.ClientId, Event.Error, new { Info = $"{asset.Id} was not transferred to client", RequestId = transferId, Operation = operation.ToJson(), Error = errMsg }.ToJson()); } }
public async Task <CommandHandlingResult> Handle(TransferEthereumCommand command, IEventPublisher eventPublisher) { var sw = new Stopwatch(); sw.Start(); try { var txRequest = await _ethereumTransactionRequestRepository.GetAsync(command.TransactionId); // todo: udpate txRequest in separated command var context = await _transactionService.GetTransactionContext <TransferContextData>(command.TransactionId.ToString()); txRequest.OperationIds = new[] { context.Transfers[0].OperationId, context.Transfers[1].OperationId }; await _ethereumTransactionRequestRepository.UpdateAsync(txRequest); ChaosKitty.Meow(); var clientAddress = await _bcnClientCredentialsRepository.GetClientAddress(txRequest.ClientId); var hotWalletAddress = _settings.HotwalletAddress; string addressFrom; string addressTo; Guid transferId; string sign; switch (txRequest.OperationType) { case OperationType.TransferToTrusted: addressFrom = clientAddress; addressTo = hotWalletAddress; transferId = txRequest.SignedTransfer.Id; sign = txRequest.SignedTransfer.Sign; break; case OperationType.TransferFromTrusted: addressFrom = hotWalletAddress; addressTo = clientAddress; transferId = txRequest.Id; sign = string.Empty; break; case OperationType.TransferBetweenTrusted: return(CommandHandlingResult.Ok()); default: _log.Error(nameof(TransferEthereumCommand), message: "Unknown transfer type"); return(CommandHandlingResult.Fail(_retryTimeout)); } var asset = await _assetsServiceWithCache.TryGetAssetAsync(txRequest.AssetId); var response = await _srvEthereumHelper.SendTransferAsync(transferId, sign, asset, addressFrom, addressTo, txRequest.Volume); ChaosKitty.Meow(); if (response.HasError && response.Error.ErrorCode != ErrorCode.OperationWithIdAlreadyExists && response.Error.ErrorCode != ErrorCode.EntityAlreadyExists) { var errorMessage = response.Error.ToJson(); _log.Error(nameof(TransferEthereumCommand), new Exception(errorMessage)); return(CommandHandlingResult.Fail(_retryTimeout)); } eventPublisher.PublishEvent(new EthereumTransferSentEvent { TransferId = transferId }); ChaosKitty.Meow(); return(CommandHandlingResult.Ok()); } finally { sw.Stop(); _log.Info("Command execution time", context: new { TxHandler = new { Handler = nameof(EthereumCommandHandler), Command = nameof(TransferEthereumCommand), Time = sw.ElapsedMilliseconds } }); } }
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); }