<commit_before>﻿using NBitcoin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WalletWasabi.Helpers
{
	public static class NBitcoinHelpers
	{
		public static string HashOutpoints(IEnumerable<OutPoint> outPoints)
		{
			var sb = new StringBuilder();
			foreach (OutPoint input in outPoints.OrderBy(x => x.Hash.ToString()).ThenBy(x => x.N))
			{
				sb.Append(ByteHelpers.ToHex(input.ToBytes()));
			}

			return HashHelpers.GenerateSha256Hash(sb.ToString());
		}

		public static BitcoinAddress ParseBitcoinAddress(string address)
		{
			try
			{
				return BitcoinAddress.Create(address, Network.RegTest);
			}
			catch (FormatException)
			{
				try
				{
					return BitcoinAddress.Create(address, Network.TestNet);
				}
				catch (FormatException)
				{
					return BitcoinAddress.Create(address, Network.Main);
				}
			}
		}

		//public static Money TakeAReasonableFee(Money outputValue)
		//{
		//	Money fee1 = Money.Coins(0.002m);
		//	Money ret = outputValue - fee;
		//	var half = outputValue / 2;
		//	if (ret <= half)
		//	{
		//		return half;
		//	}

		//	return ret;
		//}

		public static Money TakeAReasonableFee(Money outputValue)
		{
			// sanity check
			var sanity = Money.Coins(0.00001m);
			if (outputValue <= sanity)
			{
				return outputValue;
			}

			Money fee = Money.Coins(0.002m);
			var remaining = Money.Zero;

			for (int i = 0; i < 100; i++)
			{
				remaining = outputValue - fee;
				if (remaining >= sanity)
				{
					break;
				}
				fee = fee.Percentange(50);
			}

			return remaining <= 0 ? outputValue : remaining;
		}

		//public static Money TakeAReasonableFee(Money outputValue)
		//{
		//	// sanity check
		//	var sanity = Money.Coins(0.00001m);
		//	if (outputValue <= sanity)
		//	{
		//		return outputValue;
		//	}

		//	Money fee = Money.Coins(0.002m);
		//	var remaining = Money.Zero;

		//	while (true)
		//	{
		//		remaining = outputValue - fee;
		//		if (remaining > sanity)
		//		{
		//			break;
		//		}
		//		fee = fee.Percentange(50);
		//	}

		//	return remaining <= 0 ? outputValue : remaining;
		//}

		public static int CalculateVsizeAssumeSegwit(int inNum, int outNum)
		{
			var origTxSize = inNum * Constants.P2pkhInputSizeInBytes + outNum * Constants.OutputSizeInBytes + 10;
			var newTxSize = inNum * Constants.P2wpkhInputSizeInBytes + outNum * Constants.OutputSizeInBytes + 10; // BEWARE: This assumes segwit only inputs!
			var vSize = (int)Math.Ceiling(((3 * newTxSize) + origTxSize) / 4m);
			return vSize;
		}
	}
}
<commit_msg>Revise TakeAReasonableFee for good.<commit_after>﻿using NBitcoin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WalletWasabi.Helpers
{
	public static class NBitcoinHelpers
	{
		public static string HashOutpoints(IEnumerable<OutPoint> outPoints)
		{
			var sb = new StringBuilder();
			foreach (OutPoint input in outPoints.OrderBy(x => x.Hash.ToString()).ThenBy(x => x.N))
			{
				sb.Append(ByteHelpers.ToHex(input.ToBytes()));
			}

			return HashHelpers.GenerateSha256Hash(sb.ToString());
		}

		public static BitcoinAddress ParseBitcoinAddress(string address)
		{
			try
			{
				return BitcoinAddress.Create(address, Network.RegTest);
			}
			catch (FormatException)
			{
				try
				{
					return BitcoinAddress.Create(address, Network.TestNet);
				}
				catch (FormatException)
				{
					return BitcoinAddress.Create(address, Network.Main);
				}
			}
		}

		private static readonly Money[] ReasonableFees = new[] {
				Money.Coins(0.002m),
				Money.Coins(0.001m),
				Money.Coins(0.0005m),
				Money.Coins(0.0002m),
				Money.Coins(0.0001m),
				Money.Coins(0.00005m),
				Money.Coins(0.00002m),
				Money.Coins(0.00001m)
			};

		public static Money TakeAReasonableFee(Money inputValue)
		{
			Money half = inputValue / 2;

			foreach (Money fee in ReasonableFees)
			{
				Money diff = inputValue - fee;
				if (diff > half)
				{
					return diff;
				}
			}

			return half;
		}

		public static int CalculateVsizeAssumeSegwit(int inNum, int outNum)
		{
			var origTxSize = inNum * Constants.P2pkhInputSizeInBytes + outNum * Constants.OutputSizeInBytes + 10;
			var newTxSize = inNum * Constants.P2wpkhInputSizeInBytes + outNum * Constants.OutputSizeInBytes + 10; // BEWARE: This assumes segwit only inputs!
			var vSize = (int)Math.Ceiling(((3 * newTxSize) + origTxSize) / 4m);
			return vSize;
		}
	}
}

{'fraction_non_alphanumeric': 0.12265218375198009, 'fraction_numerical': 0.022629554197782304, 'mean_word_length': 2.9676840215439855, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '116506', 'n_tokens_mistral': 1910, 'n_tokens_neox': 1525, 'n_words': 324}