Ejemplo n.º 1
0
        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());
            }
        }
Ejemplo n.º 2
0
        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);
        }