Exemple #1
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);
        }