public IEnumerable <ICoin> Select(IEnumerable <ICoin> coins, IMoney target)
        {
            var selector      = new DefaultCoinSelector();
            var selectedCoins = selector.Select(coins, target).ToList();

            if (!selectedCoins.Any(o => o.Outpoint == FromOutpoint))
            {
                var fromCoin       = coins.Single(o => o.Outpoint == this.FromOutpoint);
                var fromCoinAmount = fromCoin.Amount as Money;
                var selectedAmount = selectedCoins.Select(o => o.Amount).Cast <Money>().Sum();

                if (fromCoinAmount >= selectedAmount)
                {
                    selectedCoins = new List <ICoin> {
                        fromCoin
                    }
                }
                ;
                else
                {
                    selectedCoins.Insert(0, fromCoin);
                }
            }

            return(selectedCoins);
        }
Exemple #2
0
        public async Task <Money> CalculateFees(Account account, BitcoinAddress receiver, Money amount, int blocks)
        {
            try
            {
                var rate = await EstimateSmartFee(blocks);

                _logger.LogCritical($"Estimated fee rate: {rate}");

                ExtKey key          = _masterKey.Derive(new KeyPath($"m/84'/0'/{account.Derivation}'/0/0"));
                var    sender       = key.PrivateKey.PubKey.GetSegwitAddress(Network.Main);
                var    unspentCoins = await _client.ListUnspentAsync(6, int.MaxValue, sender);

                var coins = unspentCoins.Select(c => c.AsCoin()).ToArray();
                if (coins.Select(c => c.Amount).Sum() < amount)
                {
                    _logger.LogCritical("User does not have enough funds.");
                    return(null);
                }

                var coinSelector = new DefaultCoinSelector
                {
                    GroupByScriptPubKey = false
                };

                var builder = Network.Main.CreateTransactionBuilder();
                builder.DustPrevention = false;
                var tx = builder
                         .SetCoinSelector(new DefaultCoinSelector {
                    GroupByScriptPubKey = false
                })
                         .AddCoins(coins)
                         .AddKeys(key.PrivateKey)
                         .Send(receiver, amount)
                         .SetChange(sender)
                         .SendEstimatedFees(rate)
                         .BuildTransaction(true);

                var fees = rate.GetFee(tx);

                _logger.LogCritical($"Transaction Fees: {fees}");
                _logger.LogCritical($"TransactionCheckResult: {tx.Check()}");

                if (tx.Check() == TransactionCheckResult.Success)
                {
                    return(fees);
                }
                else
                {
                    return(null);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
            }

            return(null);
        }
Exemple #3
0
		public void CanSelectCoin()
		{
			var selector = new DefaultCoinSelector(0);
			Assert.Null(selector.Select(new ICoin[] { CreateCoin("9") }, Money.Parse("10.0")));
			Assert.NotNull(selector.Select(new ICoin[] { CreateCoin("9"), CreateCoin("1") }, Money.Parse("10.0")));
			Assert.NotNull(selector.Select(new ICoin[] { CreateCoin("10.0") }, Money.Parse("10.0")));
			Assert.NotNull(selector.Select(new ICoin[] 
			{ 
				CreateCoin("5.0"),
				CreateCoin("4.0"),
				CreateCoin("11.0"),
			}, Money.Parse("10.0")));

			Assert.NotNull(selector.Select(new ICoin[] 
			{ 
				CreateCoin("3.0"),
				CreateCoin("3.0"),
				CreateCoin("3.0"),
				CreateCoin("3.0"),
				CreateCoin("3.0")
			}, Money.Parse("10.0")));
		}
Exemple #4
0
        /// <summary>
        /// Checks whether we can send the specified amount <paramref name="amount"/> of bitcoin to
        /// the wallet of the user with the Id <paramref name="id"/> parameter.
        /// </summary>
        /// <param name="id">Id of the receiver.</param>
        /// <param name="money">Amount of bitcoin to send.</param>
        public async Task <bool> BitarCanMakePayment(int id, Money amount)
        {
            try
            {
                var account = await GetAccount(id);

                ExtKey bitarKey = _masterKey.Derive(new KeyPath($"m/84'/0'/0'/0/0"));
                var    sender   = bitarKey.PrivateKey.PubKey.GetSegwitAddress(Network.Main);

                ExtKey key      = _masterKey.Derive(new KeyPath($"m/84'/0'/0'/0/0"));
                var    receiver = key.PrivateKey.PubKey.GetSegwitAddress(Network.Main);

                var unspentCoins = await _client.ListUnspentAsync(0, int.MaxValue, sender);

                if (unspentCoins == null)
                {
                    return(false);
                }

                foreach (var coin in unspentCoins)
                {
                    _logger.LogCritical(
                        $"Address: {coin.Address}\n" +
                        $"Amount: {coin.Amount}\n" +
                        $"Confirmations: {coin.Confirmations}\n" +
                        $"OutPoint: {coin.OutPoint}");
                }

                var coins = unspentCoins.Select(c => c.AsCoin()).ToArray();
                if (coins.Select(c => c.Amount).Sum() < amount)
                {
                    _logger.LogCritical("Not enough funds.");
                    _logger.LogCritical($"Sum: {coins.Select(c => c.Amount).Sum()}");
                    _logger.LogCritical($"Amount: {amount}");
                    _logger.LogCritical("==Coins==");
                    _logger.LogCritical($"{coins.Select(c => c.Amount)}");
                    _logger.LogCritical($"======");
                    _logger.LogCritical("==Coins2==");
                    _logger.LogCritical($"{coins.Count()}");
                    _logger.LogCritical($"======");

                    return(false);
                }

                var rate = await _client.EstimateSmartFeeAsync(25, EstimateSmartFeeMode.Economical);

                _logger.LogCritical($"Estimated fee rate: {rate.FeeRate}");

                var coinSelector = new DefaultCoinSelector
                {
                    GroupByScriptPubKey = false
                };

                var builder = Network.Main.CreateTransactionBuilder();
                builder.DustPrevention = false;
                var tx = builder
                         .SetCoinSelector(new DefaultCoinSelector {
                    GroupByScriptPubKey = false
                })
                         .AddCoins(coins)
                         .AddKeys(bitarKey.PrivateKey)
                         .Send(receiver, amount)
                         .SetChange(sender)
                         .SendEstimatedFees(rate.FeeRate)
                         .BuildTransaction(true);

                _logger.LogCritical(
                    $"vsize: {tx.GetVirtualSize()}\n" +
                    $"{sender} sending {amount} btc to {receiver}" +
                    $"with {builder.EstimateFees(tx, rate.FeeRate)} fees\n" +
                    $"{tx.ToString()}");

                _logger.LogCritical($"TransactionCheckResult: {tx.Check()}");

                if (tx.Check() == TransactionCheckResult.Success)
                {
                    var txId = tx.GetHash();
                    _logger.LogCritical($"TxId: {txId}");
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
            }

            return(false);
        }
Exemple #5
0
        /// <summary>
        /// Sends specified amount of bitcoin to an address.
        /// Change address is the same as the sender address.
        /// </summary>
        /// <param name="accountId">AccountId of the sender.</param>
        /// <param name="receiver">Bitcoin address to send the money to.</param>
        /// <param name="money">Amount of bitcoin to send.</param>
        /// <param name="fees">Amount of fees to be included in the transaction.</param>
        /// <remarks>
        /// Change address is the same as the sender address.
        /// </remarks>
        public async Task <uint256> SendBitcoin(int accountId, BitcoinAddress receiver, Money amount, int blocks)
        {
            try
            {
                var account = await GetAccount(accountId);

                var rate = await _client.EstimateSmartFeeAsync(blocks, EstimateSmartFeeMode.Economical);

                _logger.LogCritical($"Estimated fee rate: {rate.FeeRate}");

                ExtKey key    = _masterKey.Derive(new KeyPath($"m/84'/0'/{account.Derivation}'/0/0"));
                var    sender = key.PrivateKey.PubKey.GetSegwitAddress(Network.Main);

                UnspentCoin[] unspentCoins;

                unspentCoins = await _client.ListUnspentAsync(6, int.MaxValue, sender);


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

                foreach (var coin in unspentCoins)
                {
                    _logger.LogCritical(
                        $"Address: {coin.Address}\n" +
                        $"Amount: {coin.Amount}\n" +
                        $"Confirmations: {coin.Confirmations}\n" +
                        $"OutPoint: {coin.OutPoint}");
                }

                var coins = unspentCoins.Select(c => c.AsCoin()).ToArray();
                if (coins.Select(c => c.Amount).Sum() < amount)
                {
                    _logger.LogCritical("User does not have enough funds.");
                    return(null);
                }

                var coinSelector = new DefaultCoinSelector
                {
                    GroupByScriptPubKey = false
                };

                var builder = Network.Main.CreateTransactionBuilder();
                builder.DustPrevention = false;
                var tx = builder
                         .SetCoinSelector(new DefaultCoinSelector {
                    GroupByScriptPubKey = false
                })
                         .AddCoins(coins)
                         .AddKeys(key.PrivateKey)
                         .Send(receiver, amount)
                         .SetChange(sender)
                         .SendEstimatedFees(rate.FeeRate)
                         .BuildTransaction(true);

                var fees = rate.FeeRate.GetFee(tx);

                _logger.LogCritical(
                    $"vsize: {tx.GetVirtualSize()}\n" +
                    $"{sender} sending {amount} btc to {receiver}" +
                    $"with {fees} fees\n" +
                    $"{tx.ToString()}");

                _logger.LogCritical($"TransactionCheckResult: {tx.Check()}");

                if (tx.Check() == TransactionCheckResult.Success)
                {
                    var txId = tx.GetHash();

                    _logger.LogCritical($"TxId: {txId}");
                    // return txId; // Temporary -- Only for testing.
                    return(await _client.SendRawTransactionAsync(tx));
                }
                else
                {
                    return(null);
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
            }

            return(null);
        }