public BigInteger?EstimatePriorityFee(FeeHistoryResult feeHistory) { var rewards = feeHistory.Reward ?.Select((r) => r[0].Value) .Where((r) => r != 0) .ToList(); rewards.Sort(); if (rewards == null || rewards.Count == 0) { return(null); } var percentageIncreases = new List <BigInteger>(); for (var i = 0; i < rewards.Count - 1; i++) { var next = rewards[i + 1]; var p = ((next - rewards[i]) / rewards[i]) * 100; percentageIncreases.Add(p); } var highestIncrease = percentageIncreases.Max(); var highestIncreaseIndex = percentageIncreases.IndexOf(highestIncrease); //// If we have big increase in value, we could be considering "outliers" in our estimate //// Skip the low elements and take a new median var values = (highestIncrease > PRIORITY_FEE_INCREASE_BOUNDARY && highestIncreaseIndex >= Math.Floor((double)(rewards.Count / 2)) ? rewards.Skip(highestIncreaseIndex) : rewards).ToArray(); var valuesIndex = (int)Math.Floor((double)(values.Length / 2)); return(values[valuesIndex]); }
public Fee1559[] SuggestFees(FeeHistoryResult feeHistory, BigInteger tip) { var baseFee = feeHistory.BaseFeePerGas.Select(x => x == null? 0 : x.Value).ToArray(); var gasUsedRatio = feeHistory.GasUsedRatio; // If a block is full then the baseFee of the next block is copied. The reason is that in full blocks the minimal tip might not be enough to get included. // The last (pending) block is also assumed to end up being full in order to give some upwards bias for urgent suggestions. baseFee[baseFee.Length - 1] *= 9 / 8; for (var i = gasUsedRatio.Length - 1; i >= 0; i--) { if (gasUsedRatio[i] > (decimal)0.9) { baseFee[i] = baseFee[i + 1]; } } var order = new int[baseFee.Length]; for (var i = 0; i < baseFee.Length; i++) { order[i] = i; } #if DOTNET35 var comparer = Comparer.Create <int> #else var comparer = Comparer <int> .Create #endif ((int x, int y) => { var aa = baseFee[x]; var bb = baseFee[y]; if (aa < bb) { return(-1); } if (aa > bb) { return(1); } return(0); }); Array.Sort(order, comparer); var result = new List <Fee1559>(); BigDecimal maxBaseFee = 0; for (var timeFactor = MaxTimeFactor; timeFactor >= 0; timeFactor--) { var bf = SuggestBaseFee(baseFee, order, timeFactor); var t = new BigDecimal(tip, 0); if (bf > maxBaseFee) { maxBaseFee = bf; } else { // If a narrower time window yields a lower base fee suggestion than a wider window then we are probably in a price dip. // In this case getting included with a low tip is not guaranteed; instead we use the higher base fee suggestion // and also offer extra tip to increase the chance of getting included in the base fee dip. t += (maxBaseFee - bf) * ExtraTipRatio; bf = maxBaseFee; } result.Add(new Fee1559() { BaseFee = bf.Floor().Mantissa, MaxFeePerGas = (bf + t).Floor().Mantissa, MaxPriorityFeePerGas = t.Floor().Mantissa }); } result.Reverse(); return(result.ToArray()); }