public SwapManager( IAccount account, ISwapClient swapClient, ICurrencyQuotesProvider quotesProvider, IMarketDataRepository marketDataRepository) { _account = account ?? throw new ArgumentNullException(nameof(account)); _swapClient = swapClient ?? throw new ArgumentNullException(nameof(swapClient)); _quotesProvider = quotesProvider; _marketDataRepository = marketDataRepository ?? throw new ArgumentNullException(nameof(marketDataRepository)); var currencySwaps = _account.Currencies .Select(c => { var currencySwap = CurrencySwapCreator.Create( currency: c, account: _account); currencySwap.InitiatorPaymentConfirmed += InitiatorPaymentConfirmed; currencySwap.AcceptorPaymentConfirmed += AcceptorPaymentConfirmed; currencySwap.AcceptorPaymentSpent += AcceptorPaymentSpent; currencySwap.SwapUpdated += SwapUpdatedHandler; return(currencySwap); }); _currencySwaps = currencySwaps.ToDictionary(cs => cs.Currency); }
public static async Task <decimal> EstimateAsync( IAccount account, ICurrencyQuotesProvider quotesProvider, Func <string, Quote> feeCurrencyQuotesProvider, CurrencyConfig redeemableCurrency, WalletAddress redeemFromAddress = null, CancellationToken cancellationToken = default) { if (redeemableCurrency is BitcoinBasedConfig) { return(0m); } var feeCurrency = redeemableCurrency.FeeCurrencyName; var feeCurrencyAddress = redeemFromAddress != null ? await account .GetAddressAsync(feeCurrency, redeemFromAddress.Address, cancellationToken) .ConfigureAwait(false) : null; var redeemFee = await redeemableCurrency .GetRedeemFeeAsync(redeemFromAddress, cancellationToken) .ConfigureAwait(false); if (feeCurrencyAddress != null && feeCurrencyAddress.AvailableBalance() >= redeemFee) { return(0m); } var feeCurrencyToBaseQuote = redeemableCurrency.FeeCurrencyToBaseSymbol != null ? quotesProvider?.GetQuote(redeemableCurrency.FeeCurrencyToBaseSymbol) : null; var feeCurrencyToBasePrice = feeCurrencyToBaseQuote != null ? feeCurrencyToBaseQuote.GetMiddlePrice() : 0m; var feeCurrencyQuote = redeemableCurrency.FeeCurrencySymbol != null ? feeCurrencyQuotesProvider.Invoke(redeemableCurrency.FeeCurrencySymbol) : null; var feeCurrencyPrice = feeCurrencyQuote != null ? feeCurrencyQuote.GetMiddlePrice() : 0m; return(await redeemableCurrency .GetRewardForRedeemAsync( maxRewardPercent : redeemableCurrency.MaxRewardPercent, maxRewardPercentInBase : redeemableCurrency.MaxRewardPercentInBase, feeCurrencyToBaseSymbol : redeemableCurrency.FeeCurrencyToBaseSymbol, feeCurrencyToBasePrice : feeCurrencyToBasePrice, feeCurrencySymbol : redeemableCurrency.FeeCurrencySymbol, feeCurrencyPrice : feeCurrencyPrice, cancellationToken : cancellationToken) .ConfigureAwait(false)); }
public WebSocketAtomexClient( IConfiguration configuration, IAccount account, ISymbolsProvider symbolsProvider, ICurrencyQuotesProvider quotesProvider = null) { Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); Account = account ?? throw new ArgumentNullException(nameof(account)); Account.UnconfirmedTransactionAdded += OnUnconfirmedTransactionAddedEventHandler; SymbolsProvider = symbolsProvider ?? throw new ArgumentNullException(nameof(symbolsProvider)); QuotesProvider = quotesProvider; _cts = new CancellationTokenSource(); }
public IAtomexApp UseQuotesProvider(ICurrencyQuotesProvider quotesProvider) { QuotesProvider = quotesProvider; return(this); }
public static Task <SwapParams> EstimateSwapParamsAsync( IFromSource from, decimal fromAmount, string redeemFromAddress, CurrencyConfig fromCurrency, CurrencyConfig toCurrency, IAccount account, IAtomexClient atomexClient, ISymbolsProvider symbolsProvider, ICurrencyQuotesProvider quotesProvider, CancellationToken cancellationToken = default) { return(Task.Run(async() => { if (fromCurrency == null) { return null; } if (toCurrency == null) { return null; } var redeemFromWalletAddress = redeemFromAddress != null ? await account .GetAddressAsync(toCurrency.Name, redeemFromAddress, cancellationToken) .ConfigureAwait(false) : null; // estimate redeem fee var estimatedRedeemFee = await toCurrency .GetEstimatedRedeemFeeAsync(redeemFromWalletAddress, withRewardForRedeem: false) .ConfigureAwait(false); // estimate reward for redeem var rewardForRedeem = await RewardForRedeemHelper.EstimateAsync( account: account, quotesProvider: quotesProvider, feeCurrencyQuotesProvider: symbol => atomexClient?.GetOrderBook(symbol)?.TopOfBook(), redeemableCurrency: toCurrency, redeemFromAddress: redeemFromWalletAddress, cancellationToken: cancellationToken); // get amount reserved for active swaps var reservedForSwapsAmount = await GetAmountReservedForSwapsAsync( from: from, account: account, currency: fromCurrency) .ConfigureAwait(false); // estimate maker network fee var estimatedMakerNetworkFee = await EstimateMakerNetworkFeeAsync( fromCurrency: fromCurrency, toCurrency: toCurrency, account: account, atomexClient: atomexClient, symbolsProvider: symbolsProvider, cancellationToken: cancellationToken) .ConfigureAwait(false); var fromCurrencyAccount = account .GetCurrencyAccount(fromCurrency.Name) as IEstimatable; // estimate payment fee var estimatedPaymentFee = await fromCurrencyAccount .EstimateSwapPaymentFeeAsync( from: from, amount: fromAmount, cancellationToken: cancellationToken) .ConfigureAwait(false); // estimate max amount and max fee var maxAmountEstimation = await fromCurrencyAccount .EstimateMaxSwapPaymentAmountAsync( from: from, reserve: true, cancellationToken: cancellationToken) .ConfigureAwait(false); if (maxAmountEstimation.Error != null) { return new SwapParams { Amount = 0m, PaymentFee = estimatedPaymentFee.Value, RedeemFee = estimatedRedeemFee, RewardForRedeem = rewardForRedeem, MakerNetworkFee = estimatedMakerNetworkFee, ReservedForSwaps = reservedForSwapsAmount, Error = maxAmountEstimation.Error }; } var maxNetAmount = Math.Max(maxAmountEstimation.Amount - reservedForSwapsAmount - estimatedMakerNetworkFee, 0m); if (maxNetAmount == 0m) // insufficient funds { return new SwapParams { Amount = 0m, PaymentFee = maxAmountEstimation.Fee, RedeemFee = estimatedRedeemFee, RewardForRedeem = rewardForRedeem, MakerNetworkFee = estimatedMakerNetworkFee, ReservedForSwaps = reservedForSwapsAmount, Error = new Error( code: Errors.InsufficientFunds, description: Resources.InsufficientFundsToCoverMakerNetworkFee, details: string.Format(Resources.InsufficientFundsToCoverMakerNetworkFeeDetails, estimatedMakerNetworkFee, // required fromCurrency.Name, // currency code maxAmountEstimation.Amount - reservedForSwapsAmount)) // available }; } if (fromAmount > maxNetAmount) // amount greater than max net amount => use max amount params { return new SwapParams { Amount = Math.Max(maxNetAmount, 0m), PaymentFee = maxAmountEstimation.Fee, RedeemFee = estimatedRedeemFee, RewardForRedeem = rewardForRedeem, MakerNetworkFee = estimatedMakerNetworkFee, ReservedForSwaps = reservedForSwapsAmount, Error = new Error( code: Errors.InsufficientFunds, description: Resources.InsufficientFunds, details: string.Format(Resources.InsufficientFundsToSendAmountDetails, fromAmount, // required fromCurrency.Name, // currency code maxNetAmount)) // available }; } return new SwapParams { Amount = fromAmount, PaymentFee = estimatedPaymentFee.Value, RedeemFee = estimatedRedeemFee, RewardForRedeem = rewardForRedeem, MakerNetworkFee = estimatedMakerNetworkFee, ReservedForSwaps = reservedForSwapsAmount, Error = null }; }, cancellationToken)); }