コード例 #1
0
        public async Task <string> StartCashinAsync(IHotWalletOperation operation)
        {
            await SaveOperationAsync(operation);

            var transactionHash = await _erc20DepositContractService.RecievePaymentFromDepositContract(operation.FromAddress,
                                                                                                       operation.TokenAddress,
                                                                                                       operation.ToAddress);

            await RetryPolicy.ExecuteUnlimitedAsync(async() =>
            {
                await _hotWalletCashoutTransactionRepository.SaveAsync(new HotWalletCashoutTransaction()
                {
                    OperationId     = operation.OperationId,
                    TransactionHash = transactionHash
                });
            }, TimeSpan.FromMinutes(1).Milliseconds, _log);

            CoinTransactionMessage message = new CoinTransactionMessage()
            {
                OperationId     = operation.OperationId,
                TransactionHash = transactionHash
            };

            return(transactionHash);
        }
コード例 #2
0
        public async Task RetryCashoutAsync(IHotWalletOperation hotWalletCashout)
        {
            HotWalletCashoutMessage message = new HotWalletCashoutMessage()
            {
                OperationId = hotWalletCashout.OperationId
            };

            await _hotWalletCashoutRepository.SaveAsync(hotWalletCashout);

            await _hotWalletCashoutQueue.PutRawMessageAsync(Newtonsoft.Json.JsonConvert.SerializeObject(message));
        }
コード例 #3
0
 public static HotWalletCashoutEntity CreateEntity(IHotWalletOperation cashout)
 {
     return(new HotWalletCashoutEntity()
     {
         Amount = cashout.Amount,
         FromAddress = cashout.FromAddress,
         OperationId = cashout.OperationId,
         PartitionKey = Key,
         ToAddress = cashout.ToAddress,
         TokenAddress = cashout.TokenAddress,
         OperationType = cashout.OperationType
     });
 }
コード例 #4
0
        public async Task EnqueueCashoutAsync(IHotWalletOperation hotWalletCashout)
        {
            if (hotWalletCashout == null)
            {
                return;
            }

            var existingCashout = await _hotWalletCashoutRepository.GetAsync(hotWalletCashout.OperationId);

            if (existingCashout != null)
            {
                throw new ClientSideException(ExceptionType.EntityAlreadyExists, "Operation with Id was enqueued before");
            }

            hotWalletCashout.OperationType = HotWalletOperationType.Cashout;
            await RetryCashoutAsync(hotWalletCashout);
        }
コード例 #5
0
        public async Task <string> StartCashinAsync(IHotWalletOperation operation)
        {
            await SaveOperationAsync(operation);

            var transactionHash = await _erc20DepositContractService.RecievePaymentFromDepositContract(operation.FromAddress,
                                                                                                       operation.TokenAddress,
                                                                                                       operation.ToAddress);

            await _hotWalletCashoutTransactionRepository.SaveAsync(new HotWalletCashoutTransaction()
            {
                OperationId     = operation.OperationId,
                TransactionHash = transactionHash
            });

            CoinTransactionMessage message = new CoinTransactionMessage()
            {
                OperationId     = operation.OperationId,
                TransactionHash = transactionHash
            };

            return(transactionHash);
        }
コード例 #6
0
        public async Task SaveAsync(IHotWalletOperation cashout)
        {
            HotWalletCashoutEntity entity = HotWalletCashoutEntity.CreateEntity(cashout);

            await _table.InsertOrReplaceAsync(entity);
        }
コード例 #7
0
 public async Task SaveOperationAsync(IHotWalletOperation operation)
 {
     await _hotWalletCashoutRepository.SaveAsync(operation);
 }
コード例 #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="hotWalletCashout"></param>
        /// <returns>transaction hash</returns>
        public async Task <string> StartCashoutAsync(string operationId)
        {
            IHotWalletOperation cashout = await _hotWalletCashoutRepository.GetAsync(operationId);

            if (cashout == null || cashout.OperationType != HotWalletOperationType.Cashout)
            {
                await _log.WriteWarningAsync(nameof(HotWalletService),
                                             nameof(StartCashoutAsync),
                                             $"operationId - {operationId}",
                                             "No cashout info for operation",
                                             DateTime.UtcNow);

                return(null);
            }

            var gasPrice = await _gasPriceRepository.GetAsync();

            var currentGasPriceHex = await _web3.Eth.GasPrice.SendRequestAsync();

            var        currentGasPrice  = currentGasPriceHex.Value;
            BigInteger selectedGasPrice = currentGasPrice * _baseSettings.GasPricePercentage / 100;

            if (selectedGasPrice > gasPrice.Max)
            {
                selectedGasPrice = gasPrice.Max;
            }
            else if (selectedGasPrice < gasPrice.Min)
            {
                selectedGasPrice = gasPrice.Min;
            }

            string        transactionForSigning = null;
            string        signedTransaction     = null;
            string        transactionHash       = null;
            bool          isErc20Transfer       = !string.IsNullOrEmpty(cashout.TokenAddress);
            SemaphoreSlim semaphore             = _semaphores.GetOrAdd(cashout.FromAddress, f => new SemaphoreSlim(1, 1));

            try
            {
                await semaphore.WaitAsync();

                //Erc20 transfer
                if (isErc20Transfer)
                {
                    transactionForSigning = await _erc20PrivateWalletService.GetTransferTransactionRaw(new Lykke.Service.EthereumCore.BusinessModels.PrivateWallet.Erc20Transaction()
                    {
                        FromAddress  = cashout.FromAddress,
                        GasAmount    = Constants.GasForHotWalletTransaction,
                        GasPrice     = selectedGasPrice,
                        ToAddress    = cashout.ToAddress,
                        TokenAddress = cashout.TokenAddress,
                        TokenAmount  = cashout.Amount,
                        Value        = 0,
                    }, useTxPool : true);
                }
                //Eth transfer
                else
                {
                    transactionForSigning = await _privateWalletService.GetTransactionForSigning(new Lykke.Service.EthereumCore.BusinessModels.PrivateWallet.EthTransaction()
                    {
                        FromAddress = cashout.FromAddress,
                        GasAmount   = Constants.GasForHotWalletTransaction,
                        GasPrice    = selectedGasPrice,
                        ToAddress   = cashout.ToAddress,
                        Value       = cashout.Amount
                    }, useTxPool : true);
                }

                signedTransaction = await _signatureService.SignRawTransactionAsync(cashout.FromAddress, transactionForSigning);

                if (string.IsNullOrEmpty(signedTransaction))
                {
                    throw new ClientSideException(ExceptionType.WrongSign, "Wrong signature");
                }

                var transactionExecutionCosts =
                    await _privateWalletService.EstimateTransactionExecutionCost(cashout.FromAddress, signedTransaction);

                if (!transactionExecutionCosts.IsAllowed)
                {
                    throw new Exception($"Transaction will not be successfull {JsonSerialisersExt.ToJson(cashout)}");
                }

                transactionHash = isErc20Transfer ? await _erc20PrivateWalletService.SubmitSignedTransaction(cashout.FromAddress, signedTransaction) :
                                  await _privateWalletService.SubmitSignedTransaction(cashout.FromAddress, signedTransaction);
            }
            finally
            {
                semaphore.Release();
            }

            if (string.IsNullOrEmpty(transactionHash))
            {
                throw new Exception("Transaction was not sent");
            }

            CoinTransactionMessage message = new CoinTransactionMessage()
            {
                OperationId     = operationId,
                TransactionHash = transactionHash
            };

            await _hotWalletCashoutTransactionRepository.SaveAsync(new HotWalletCashoutTransaction()
            {
                OperationId     = operationId,
                TransactionHash = transactionHash
            });

            await _hotWalletTransactionMonitoringQueue.PutRawMessageAsync(Newtonsoft.Json.JsonConvert.SerializeObject(message));

            return(transactionHash);
        }
コード例 #9
0
        public async Task Execute(LykkePayErc20TransferMessage transaction, QueueTriggeringContext context)
        {
            IHotWalletOperation operation = null;

            if (string.IsNullOrEmpty(transaction?.OperationId))
            {
                await _logger.WriteWarningAsync(nameof(Erc20DepositTransferStarterJob),
                                                "Execute", "", "Empty message skipped");

                return;
            }

            try
            {
                operation = await _operationsRepository.GetAsync(transaction.OperationId);

                if (operation == null)
                {
                    await _logger.WriteWarningAsync(nameof(Erc20DepositTransferStarterJob),
                                                    "Execute", transaction.ToJson(),
                                                    $"No operation for id {transaction?.OperationId} message skipped");

                    return;
                }

                var transactionSenderAddress = _settings.Airlines.AirlinesAddress;
                var balance =
                    await _ercInterfaceService.GetPendingBalanceForExternalTokenAsync(operation.FromAddress,
                                                                                      operation.TokenAddress);

                if (balance < operation.Amount)
                {
                    await _logger.WriteWarningAsync(nameof(Erc20DepositTransferStarterJob),
                                                    "Execute", transaction.ToJson(),
                                                    $"Sendig Failed Event: DepositAddress: {operation.FromAddress}, " +
                                                    $"TokenAddress: {operation.TokenAddress}, " +
                                                    $"DesiredAmount: {operation.Amount} " +
                                                    $"CurrentBalance {balance}");

                    TransferEvent @event = new TransferEvent(transaction.OperationId,
                                                             "",
                                                             operation.Amount.ToString(),
                                                             operation.TokenAddress,
                                                             operation.FromAddress,
                                                             operation.ToAddress,
                                                             "",
                                                             0,
                                                             SenderType.EthereumCore,
                                                             EventType.NotEnoughFunds,
                                                             WorkflowType.Airlines,
                                                             DateTime.UtcNow);

                    await _rabbitQueuePublisher.PublshEvent(@event);

                    return;
                }

                var trHash = await Erc223SharedService.StartDepositTransferAsync(_web3,
                                                                                 _settings.EthereumCore.Erc223DepositContract.Abi,
                                                                                 transactionSenderAddress,
                                                                                 operation.FromAddress,
                                                                                 operation.TokenAddress,
                                                                                 operation.ToAddress,
                                                                                 operation.Amount);

                await _hotWalletTransactionRepository.SaveAsync(new HotWalletCashoutTransaction()
                {
                    OperationId     = transaction.OperationId,
                    TransactionHash = trHash
                });

                var message = new CoinTransactionMessage()
                {
                    OperationId     = transaction.OperationId,
                    TransactionHash = trHash
                };

                //Observe transaction
                await _transactionMonitoringQueue.PutRawMessageAsync(message.ToJson());

                var notificationMessage = new LykkePayErc20TransferNotificationMessage()
                {
                    OperationId     = transaction.OperationId,
                    TransactionHash = trHash,
                    Balance         = operation.Amount.ToString()
                };

                await _transactionStartedNotificationQueue.PutRawMessageAsync(notificationMessage.ToJson());
            }
            catch (ClientSideException ex)
            {
                if (operation == null)
                {
                    return;
                }

                TransferEvent @event = new TransferEvent(transaction.OperationId,
                                                         "",
                                                         operation.Amount.ToString(),
                                                         operation.TokenAddress,
                                                         operation.FromAddress,
                                                         operation.ToAddress,
                                                         "",
                                                         0,
                                                         SenderType.EthereumCore,
                                                         EventType.Failed,
                                                         WorkflowType.Airlines,
                                                         DateTime.UtcNow);

                _logger.WriteWarning("Execute", operation.ToJson(), "ClientSideException", ex);

                await _rabbitQueuePublisher.PublshEvent(@event);
            }
            catch (Exception ex)
            {
                if (transaction == null)
                {
                    return;
                }

                if (ex.Message != transaction.LastError)
                {
                    _logger.WriteWarning("Execute", transaction.ToJson(), $"{transaction.OperationId}");
                }

                transaction.LastError = ex.Message;
                transaction.DequeueCount++;
                context.MoveMessageToEnd(transaction.ToJson());
                context.SetCountQueueBasedDelay(_settings.EthereumCore.MaxQueueDelay, 200);

                _logger.WriteError("Execute", transaction.ToJson(), ex);
            }
        }
コード例 #10
0
        public async Task Execute(LykkePayErc20TransferMessage transaction, QueueTriggeringContext context)
        {
            IHotWalletOperation operation = null;

            if (string.IsNullOrEmpty(transaction?.OperationId))
            {
                await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob),
                                                "Execute", "", "Empty message skipped");

                return;
            }

            try
            {
                operation = await _operationsRepository.GetAsync(transaction.OperationId);

                if (operation == null)
                {
                    await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob),
                                                    "Execute", transaction.ToJson(),
                                                    $"No operation for id {transaction?.OperationId} message skipped");

                    return;
                }

                var transactionSenderAddress = _settings.LykkePay.LykkePayAddress;
                var balance =
                    await _ercInterfaceService.GetPendingBalanceForExternalTokenAsync(operation.FromAddress,
                                                                                      operation.TokenAddress);

                if (balance == 0)
                {
                    await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob),
                                                    "Execute", transaction.ToJson(),
                                                    $"DepositAddress: {operation.FromAddress}, TokenAddress: {operation.TokenAddress}");

                    //TODO: Transaction Failed

                    return;
                }

                var trHash = await Erc20SharedService.StartDepositTransferAsync(_web3, _settings.EthereumCore,
                                                                                transactionSenderAddress,
                                                                                operation.FromAddress, operation.TokenAddress, operation.ToAddress);

                await _hotWalletTransactionRepository.SaveAsync(new HotWalletCashoutTransaction()
                {
                    OperationId     = transaction.OperationId,
                    TransactionHash = trHash
                });

                var message = new CoinTransactionMessage()
                {
                    OperationId     = transaction.OperationId,
                    TransactionHash = trHash
                };

                //Observe transaction
                await _transactionMonitoringQueue.PutRawMessageAsync(
                    Newtonsoft.Json.JsonConvert.SerializeObject(message));

                var notificationMessage = new LykkePayErc20TransferNotificationMessage()
                {
                    OperationId     = transaction.OperationId,
                    TransactionHash = trHash,
                    Balance         = balance.ToString() //At the starting moment(may change at the end of the execution)
                };

                await _transactionStartedNotificationQueue.PutRawMessageAsync(
                    Newtonsoft.Json.JsonConvert.SerializeObject(notificationMessage));
            }
            catch (ClientSideException ex)
            {
                if (operation == null)
                {
                    return;
                }

                TransferEvent @event = new TransferEvent(transaction.OperationId,
                                                         "",
                                                         operation.Amount.ToString(),
                                                         operation.TokenAddress,
                                                         operation.FromAddress,
                                                         operation.ToAddress,
                                                         "",
                                                         0,
                                                         SenderType.EthereumCore,
                                                         EventType.Failed,
                                                         WorkflowType.LykkePay,
                                                         DateTime.UtcNow);

                await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute",
                                                operation.ToJson(), ex);

                await _rabbitQueuePublisher.PublshEvent(@event);
            }
            catch (Exception ex)
            {
                if (transaction == null)
                {
                    return;
                }

                if (ex.Message != transaction.LastError)
                {
                    await _logger.WriteWarningAsync(nameof(LykkePayErc20DepositTransferStarterJob),
                                                    "Execute", transaction.ToJson(), "transaction.OperationId");
                }

                transaction.LastError = ex.Message;
                transaction.DequeueCount++;
                context.MoveMessageToEnd(transaction.ToJson());
                context.SetCountQueueBasedDelay(_settings.EthereumCore.MaxQueueDelay, 200);

                await _logger.WriteErrorAsync(nameof(LykkePayErc20DepositTransferStarterJob), "Execute",
                                              transaction.ToJson(), ex);
            }
        }