public async Task <BrokerSaleResult> Sale(BrokerSaleParams model)
        {
            _logger.LogInformation("Sale: {@params}", model);

            ValidateSaleParams(model);

            // payment calculation
            var btcRate = await _rateCache.GetRateToUsd(model.PayCurrency);

            var graftRate = await _rateCache.GetRateToUsd("GRFT");

            var btcAmount   = model.SaleAmount / btcRate;
            var graftAmount = model.SaleAmount / graftRate;

            var serviceProviderFee = graftAmount * (decimal)model.ServiceProviderFee;
            var exchangeBrokerFee  = graftAmount * _settings.ExchangeBrokerFee;

            var merchantAmount = graftAmount - serviceProviderFee - exchangeBrokerFee;

            var payment = new Payment
            {
                PaymentId = model.PaymentId ?? Guid.NewGuid().ToString(),
                CreatedAt = DateTime.UtcNow,
                Status    = PaymentStatus.Waiting,

                SaleAmount   = model.SaleAmount,
                SaleCurrency = model.SaleCurrency,

                PayToSaleRate   = btcRate,
                GraftToSaleRate = graftRate,

                PayCurrency = model.PayCurrency,
                PayAmount   = btcAmount,

                ServiceProviderFee = serviceProviderFee,
                ExchangeBrokerFee  = exchangeBrokerFee,
                MerchantAmount     = merchantAmount,

                ServiceProviderWallet = model.ServiceProviderWallet,
                MerchantWallet        = model.MerchantWallet,

                MerchantTransactionStatus = GraftTransactionStatus.New,
                ProviderTransactionStatus = GraftTransactionStatus.New
            };

            await _cryptoProviderService.CreateAddress(payment);

            _cache.Set(payment.PaymentId, payment, DateTimeOffset.Now.AddMinutes(_settings.PaymentTimeoutMinutes));

            _db.Payment.Add(payment);
            await _db.SaveChangesAsync();

            var res = GetSaleResult(payment);

            _logger.LogInformation("Sale Result: {@params}", res);
            return(res);
        }
        void ValidateSaleParams(BrokerSaleParams model)
        {
            if (model.SaleAmount <= 0)
            {
                throw new ApiException(ErrorCode.InvalidAmount);
            }

            if (string.IsNullOrWhiteSpace(model.SaleCurrency))
            {
                throw new ApiException(ErrorCode.SaleCurrencyEmpty);
            }

            if (model.SaleCurrency != "USD")
            {
                throw new ApiException(ErrorCode.SaleCurrencyNotSupported, model.SaleCurrency);
            }

            if (string.IsNullOrWhiteSpace(model.PayCurrency))
            {
                throw new ApiException(ErrorCode.PayCurrencyEmpty);
            }

            if (!_rateCache.IsSupported(model.PayCurrency))
            {
                throw new ApiException(ErrorCode.PayCurrencyNotSupported, model.PayCurrency);
            }

            if (model.ServiceProviderFee < 0 || model.ServiceProviderFee > _settings.MaxServiceProviderFee)
            {
                throw new ApiException(ErrorCode.InvalidServiceProviderFee);
            }

            if (model.ServiceProviderFee > 0 && string.IsNullOrWhiteSpace(model.ServiceProviderWallet))
            {
                throw new ApiException(ErrorCode.ServiceProviderWalletEmpty);
            }

            if (string.IsNullOrWhiteSpace(model.MerchantWallet))
            {
                throw new ApiException(ErrorCode.MerchantWalletEmpty);
            }
        }
        public async Task <IActionResult> Sale([FromBody] BrokerSaleParams model)
        {
            var res = await _paymentService.Sale(model);

            return(Ok(res));
        }