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); }
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)); }
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 }); }
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)); }