Beispiel #1
0
        public override async Task <decimal> GetRewardForRedeemAsync(
            decimal maxRewardPercent,
            decimal maxRewardPercentInBase,
            string feeCurrencyToBaseSymbol,
            decimal feeCurrencyToBasePrice,
            string feeCurrencySymbol            = null,
            decimal feeCurrencyPrice            = 0,
            CancellationToken cancellationToken = default)
        {
            var rewardForRedeemInEth = await base.GetRewardForRedeemAsync(
                maxRewardPercent : maxRewardPercent,
                maxRewardPercentInBase : maxRewardPercentInBase,
                feeCurrencyToBaseSymbol : feeCurrencyToBaseSymbol,
                feeCurrencyToBasePrice : feeCurrencyToBasePrice,
                feeCurrencySymbol : feeCurrencySymbol,
                feeCurrencyPrice : feeCurrencyPrice,
                cancellationToken : cancellationToken);

            if (feeCurrencySymbol == null || feeCurrencyPrice == 0)
            {
                return(0m);
            }

            return(AmountHelper.RoundDown(feeCurrencySymbol.IsBaseCurrency(Name)
                ? rewardForRedeemInEth / feeCurrencyPrice
                : rewardForRedeemInEth *feeCurrencyPrice, DigitsMultiplier));
        }
        private decimal RequiredAmountInTokens(Swap swap, Erc20Config erc20)
        {
            var requiredAmountInERC20 = AmountHelper.QtyToSellAmount(swap.Side, swap.Qty, swap.Price, erc20.DigitsMultiplier);

            // maker network fee
            if (swap.MakerNetworkFee > 0 && swap.MakerNetworkFee < requiredAmountInERC20) // network fee size check
            {
                requiredAmountInERC20 += AmountHelper.RoundDown(swap.MakerNetworkFee, erc20.DigitsMultiplier);
            }

            return(requiredAmountInERC20);
        }
Beispiel #3
0
        public static decimal CalculateRewardForRedeem(
            decimal redeemFee,
            string redeemFeeCurrency,
            decimal redeemFeeDigitsMultiplier,
            decimal maxRewardPercent,
            decimal maxRewardPercentValue,
            string feeCurrencyToBaseSymbol,
            decimal feeCurrencyToBasePrice,
            decimal baseDigitsMultiplier = 2)
        {
            var redeemFeeInBase = AmountHelper.RoundDown(feeCurrencyToBaseSymbol.IsBaseCurrency(redeemFeeCurrency)
                ? redeemFee * feeCurrencyToBasePrice
                : redeemFee / feeCurrencyToBasePrice, baseDigitsMultiplier);

            var k = maxRewardPercentValue / (decimal)Math.Log((double)((1 - maxRewardPercent) / MaxRewardForRedeemDeviation));
            var p = (1 - maxRewardPercent) / (decimal)Math.Exp((double)(redeemFeeInBase / k)) + maxRewardPercent;

            return(AmountHelper.RoundDown(redeemFee * (1 + p), redeemFeeDigitsMultiplier));
        }
Beispiel #4
0
        protected virtual async Task <EthereumTransaction> CreatePaymentTxAsync(
            Swap swap,
            int lockTimeInSeconds,
            CancellationToken cancellationToken = default)
        {
            var ethConfig = EthConfig;

            Log.Debug("Create payment transaction from address {@address} for swap {@swapId}", swap.FromAddress, swap.Id);

            var requiredAmountInEth = AmountHelper.QtyToSellAmount(swap.Side, swap.Qty, swap.Price, ethConfig.DigitsMultiplier);

            // maker network fee
            if (swap.MakerNetworkFee > 0 && swap.MakerNetworkFee < requiredAmountInEth) // network fee size check
            {
                requiredAmountInEth += AmountHelper.RoundDown(swap.MakerNetworkFee, ethConfig.DigitsMultiplier);
            }

            var refundTimeStampUtcInSec = new DateTimeOffset(swap.TimeStamp.ToUniversalTime().AddSeconds(lockTimeInSeconds)).ToUnixTimeSeconds();

            var rewardForRedeemInEth = swap.PartyRewardForRedeem;

            var walletAddress = await _account
                                .GetAddressAsync(swap.FromAddress, cancellationToken)
                                .ConfigureAwait(false);

            var gasPrice = await ethConfig
                           .GetGasPriceAsync(cancellationToken)
                           .ConfigureAwait(false);

            var balanceInEth = walletAddress.Balance;

            Log.Debug("Available balance: {@balance}", balanceInEth);

            var feeAmountInEth = rewardForRedeemInEth == 0
                ? ethConfig.InitiateFeeAmount(gasPrice)
                : ethConfig.InitiateWithRewardFeeAmount(gasPrice);

            if (balanceInEth < feeAmountInEth + requiredAmountInEth)
            {
                Log.Warning(
                    "Insufficient funds at {@address}. Balance: {@balance}, required: {@required}, " +
                    "feeAmount: {@feeAmount}, missing: {@result}.",
                    walletAddress.Address,
                    balanceInEth,
                    requiredAmountInEth,
                    feeAmountInEth,
                    balanceInEth - feeAmountInEth - requiredAmountInEth);

                return(null);
            }

            var nonceResult = await((IEthereumBlockchainApi)ethConfig.BlockchainApi)
                              .GetTransactionCountAsync(walletAddress.Address, pending: false, cancellationToken)
                              .ConfigureAwait(false);

            if (nonceResult.HasError)
            {
                Log.Error($"Getting nonce error: {nonceResult.Error.Description}");
                return(null);
            }

            TransactionInput txInput;

            var message = new InitiateFunctionMessage
            {
                HashedSecret    = swap.SecretHash,
                Participant     = swap.PartyAddress,
                RefundTimestamp = refundTimeStampUtcInSec,
                AmountToSend    = EthereumConfig.EthToWei(requiredAmountInEth),
                FromAddress     = walletAddress.Address,
                GasPrice        = EthereumConfig.GweiToWei(gasPrice),
                Nonce           = nonceResult.Value,
                RedeemFee       = EthereumConfig.EthToWei(rewardForRedeemInEth)
            };

            var initiateGasLimit = rewardForRedeemInEth == 0
                ? ethConfig.InitiateGasLimit
                : ethConfig.InitiateWithRewardGasLimit;

            message.Gas = await EstimateGasAsync(message, new BigInteger(initiateGasLimit))
                          .ConfigureAwait(false);

            txInput = message.CreateTransactionInput(ethConfig.SwapContractAddress);

            return(new EthereumTransaction(ethConfig.Name, txInput)
            {
                Type = BlockchainTransactionType.Output | BlockchainTransactionType.SwapPayment
            });
        }
Beispiel #5
0
        public static Task <SwapPriceEstimation> EstimateSwapPriceAsync(
            decimal amount,
            AmountType amountType,
            CurrencyConfig fromCurrency,
            CurrencyConfig toCurrency,
            IAccount account,
            IAtomexClient atomexClient,
            ISymbolsProvider symbolsProvider,
            CancellationToken cancellationToken = default)
        {
            return(Task.Run(() =>
            {
                if (fromCurrency == null)
                {
                    return null;
                }

                if (toCurrency == null)
                {
                    return null;
                }

                var symbol = symbolsProvider
                             .GetSymbols(account.Network)
                             .SymbolByCurrencies(fromCurrency, toCurrency);

                if (symbol == null)
                {
                    return null;
                }

                var side = symbol.OrderSideForBuyCurrency(toCurrency);
                var orderBook = atomexClient.GetOrderBook(symbol);

                if (orderBook == null)
                {
                    return null;
                }

                var baseCurrency = account.Currencies.GetByName(symbol.Base);

                var isSoldAmount = amountType == AmountType.Sold;

                var(estimatedOrderPrice, estimatedPrice) = orderBook.EstimateOrderPrices(
                    side: side,
                    amount: amount,
                    amountDigitsMultiplier: isSoldAmount
                        ? fromCurrency.DigitsMultiplier
                        : toCurrency.DigitsMultiplier,
                    qtyDigitsMultiplier: baseCurrency.DigitsMultiplier,
                    amountType: amountType);

                var(estimatedMaxFromAmount, estimatedMaxToAmount) = orderBook.EstimateMaxAmount(side, fromCurrency.DigitsMultiplier);

                var isNoLiquidity = amount != 0 && estimatedOrderPrice == 0;

                var oppositeAmount = isSoldAmount
                    ? symbol.IsBaseCurrency(toCurrency.Name)
                        ? estimatedPrice != 0
                            ? AmountHelper.RoundDown(amount / estimatedPrice, toCurrency.DigitsMultiplier)
                            : 0m
                        : AmountHelper.RoundDown(amount * estimatedPrice, toCurrency.DigitsMultiplier)
                    : symbol.IsBaseCurrency(toCurrency.Name)
                        ? AmountHelper.RoundDown(amount * estimatedPrice, fromCurrency.DigitsMultiplier)
                        : estimatedPrice != 0
                            ? AmountHelper.RoundDown(amount / estimatedPrice, fromCurrency.DigitsMultiplier)
                            : 0m;

                return new SwapPriceEstimation
                {
                    FromAmount = isSoldAmount ? amount : oppositeAmount,
                    ToAmount = isSoldAmount ? oppositeAmount : amount,
                    OrderPrice = estimatedOrderPrice,
                    Price = estimatedPrice,
                    MaxFromAmount = estimatedMaxFromAmount,
                    MaxToAmount = estimatedMaxToAmount,
                    IsNoLiquidity = isNoLiquidity
                };
            }, cancellationToken));
        }