public class ActionScript { private ContextProvider Context = ScriptManager.Context; public bool Execute(List list) { Context.System.LogMessage("Awesome Profit Switching: " + list.Count + " miner(s)."); MinerProcessor minerProcessor = new MinerProcessor(); List poolProfitList = new List(); // Download latest statistics before we check profitability Context.OnlineService.UpdateStatisticsAll(); Context.System.LogMessage("Awesome Profit Switching: Statistics updated"); // Process each selected miner foreach (IMinerBase miner in list) { if (!miner.IsRunningState) continue; Context.System.LogMessage("Awesome Profit Switching processing: " + miner.GetDescription()); minerProcessor.Run(miner); } return true; } } class MinerProcessor { private ContextProvider Context = ScriptManager.Context; public void Run(IMinerBase miner) { ISinglePool currentPool = Context.Pool.GetActive(miner); if (currentPool != null) { // Each miner has its own list of pools List minerPoolProfitList = new List(); List preservePoolList = new List(); // Get all active pools for the miner (for Primitive miners, include Disabled pools) List coinPoolList = Context.Pool.GetActivePoolList(miner, false, true, !miner.IsClassic); // Add all pools into minerPoolProfitList if it should be target for profit switching // or to preservePoolList if we can't switch away from that pool foreach (ISinglePool coinPool in coinPoolList) { PoolProfit poolProfit = new PoolProfit(coinPool); if (poolProfit.IsValid()) { IPoolStatus poolStatus = miner.GetPoolStatus(poolProfit.Pool); if (poolStatus != null) { poolProfit.Priority = poolStatus.GetPriority(); if (poolProfit.IsPreservePool) preservePoolList.Add(poolProfit); else minerPoolProfitList.Add(poolProfit); } else Context.System.LogMessage(" No pool status available: " + poolProfit.Pool.GetDescription()); } else if (poolProfit.Pool != null) Context.System.LogMessage(" Pool profit information not available: " + poolProfit.Pool.GetDescription()); } // Sort to get highest profit first in list minerPoolProfitList.Sort((item1, item2) => item2.GetProfit().CompareTo(item1.GetProfit())); // Sort preseve pools by Priority order, lowest number first preservePoolList.Sort((item1, item2) => item1.Priority.CompareTo(item2.Priority)); LogList("Profitability information", minerPoolProfitList); LogList("Preserve list", preservePoolList); // Construct list of pools in priority order. First the pools to preserve at top priority and then by profitability List priorityList = new List(); preservePoolList.ForEach(item => priorityList.Add(item.Pool)); minerPoolProfitList.ForEach(item => priorityList.Add(item.Pool)); if (!miner.IsClassic) { // For CcMiner and Eth miner if (coinPoolList.Count > 0 && priorityList.Count > 0 && coinPoolList[0].ID != priorityList[0].ID) { Context.System.LogMessage("Profitability, Changing to pool: " + priorityList[0].GetDescription()); Context.Pool.Prioritize(miner, priorityList[0]); } else Context.System.LogMessage("Profitability, Already using pool: " + priorityList[0].GetDescription()); } else { Context.Pool.SetPriority(miner, priorityList); } } } private void LogList(string message, List profitList) { string info = string.Empty; foreach (PoolProfit poolProfit in profitList) info += " " + poolProfit.Pool.GetDescription() + ", Url: " + poolProfit.Pool.GetUrl() + ", Profit: " + poolProfit.GetProfit() + ", Priority: " + poolProfit.Priority + "\r\n"; Context.System.LogMessage(message + ":\r\n " + info.Trim()); } } class PoolProfit { // To disable an algorithm, set factor to 0. // To make it less likely to be used, set to lower value than 1.0. // Using 0.5 would require the profit to be two times as high before selecting the algorithm private Dictionary algorithmFactor = new Dictionary { { CoinAlgorithm.Scrypt, 1.0 }, { CoinAlgorithm.ScryptAN, 1.0 }, { CoinAlgorithm.SHA3, 1.0 }, { CoinAlgorithm.X11, 1.0 }, { CoinAlgorithm.X13, 1.0 }, { CoinAlgorithm.X15, 1.0 }, { CoinAlgorithm.Nist5, 1.0 }, { CoinAlgorithm.NeoScrypt, 1.0 }, { CoinAlgorithm.Qubit, 1.0 }, { CoinAlgorithm.WhirlpoolX, 1.0 }, { CoinAlgorithm.Quark, 1.0 }, { CoinAlgorithm.Lyra2REv2, 1.0 }, }; private Dictionary poolServices = new Dictionary { // NiceHash standard pools {"nicehash.com:3333", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Scrypt)}, {"nicehash.com:3335", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.ScryptAN)}, {"nicehash.com:3338", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.SHA3)}, {"nicehash.com:3336", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.X11)}, {"nicehash.com:3337", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.X13)}, {"nicehash.com:3339", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.X15)}, {"nicehash.com:3340", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Nist5)}, {"nicehash.com:3341", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.NeoScrypt)}, {"nicehash.com:3342", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Lyra2RE)}, {"nicehash.com:3343", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.WhirlpoolX)}, {"nicehash.com:3344", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Qubit)}, {"nicehash.com:3345", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Quark)}, {"nicehash.com:3347", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Lyra2REv2)}, {"nicehash.com:3354", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Decred)}, {"nicehash.com:3356", new PoolService(OnlineServiceType.NiceHash, CoinAlgorithm.Lbry)}, // LTCRabbit {"ltcrabbit.com:3333", new PoolService(OnlineServiceType.LtcRabbit, CoinAlgorithm.Scrypt)}, {"ltcrabbit.com:3335", new PoolService(OnlineServiceType.LtcRabbit, CoinAlgorithm.Scrypt)}, {"ltcrabbit.com:3336", new PoolService(OnlineServiceType.LtcRabbit, CoinAlgorithm.Scrypt)}, {"ltcrabbit.com:3337", new PoolService(OnlineServiceType.LtcRabbit, CoinAlgorithm.Scrypt)}, {"ltcrabbit.com:3338", new PoolService(OnlineServiceType.LtcRabbit, CoinAlgorithm.Scrypt)}, {"ltcrabbit.com:3332", new PoolService(OnlineServiceType.LtcRabbit, CoinAlgorithm.X11)}, // zpool.ca {"zpool.ca:3433", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.Scrypt)}, {"zpool.ca:3533", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.X11)}, {"zpool.ca:3633", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.X13)}, {"zpool.ca:3733", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.X15)}, {"zpool.ca:3833", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.Nist5)}, {"zpool.ca:4233", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.NeoScrypt)}, {"zpool.ca:4733", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.Qubit)}, {"zpool.ca:4033", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.Quark)}, {"zpool.ca:4533", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.Lyra2REv2)}, {"zpool.ca:5744", new PoolService(OnlineServiceType.Zpool, CoinAlgorithm.Decred)}, }; // Always put these pools on top priority, before all profitability pools private List preservePoolServices = new List() { "betarigs.com", "miningrigrentals.com", }; public bool IsPreservePool { get; private set; } public int Priority { get; set; } public ISinglePool Pool { get; private set; } public OnlineServiceType ServiceType { get; private set; } public CoinAlgorithm Algorithm { get; private set; } public double Profit { get; private set; } private PoolServiceClass PoolClass { get; set; } private int Port { get; set; } private class PoolService { public OnlineServiceType ServiceType { get; private set; } public CoinAlgorithm Algorithm { get; private set; } public PoolService(OnlineServiceType serviceType, CoinAlgorithm algorithm) { ServiceType = serviceType; Algorithm = algorithm; } } private enum PoolServiceClass { UserDefined, MultiCoinPool, SingleCoinPool, } public PoolProfit(ISinglePool pool) { Pool = pool; if (pool != null) { string url = pool.GetUrl().ToLower(); // Check if a preserve-pool like Betarigs that we shouldn't prioritize away IsPreservePool = preservePoolServices.Find(item => url.Contains(item)) != null; if (!IsPreservePool) { // Search for ServiceType (supported multi-pools) using Pool URL PoolService poolService = null; foreach (KeyValuePair kvp in poolServices) { if (url.Contains(kvp.Key)) { poolService = kvp.Value; break; } } if (poolService != null) { // Multi-pool service ServiceType = poolService.ServiceType; Algorithm = poolService.Algorithm; PoolClass = PoolServiceClass.MultiCoinPool; } else { // Check if known single coin pool (TradeMyBit) OnlineServiceType serviceType; CoinAlgorithm algorithm; int port; if (ScriptManager.Context.OnlineService.GetKnownSingleCoinPool(url, out serviceType, out algorithm, out port)) { ServiceType = serviceType; Algorithm = algorithm; Port = port; PoolClass = PoolServiceClass.SingleCoinPool; } else // Any other single coin pool { PoolClass = PoolServiceClass.UserDefined; Algorithm = ScriptManager.Context.Pool.GetPoolAlgorithm(pool); } } } } } public double GetProfit() { if (PoolClass == PoolServiceClass.MultiCoinPool) { IOnlineServiceEntry entry = ScriptManager.Context.OnlineService.GetEntry(ServiceType, Algorithm); return (entry != null) ? entry.BtcPerNormalizedMhsPerDay * GetAlgorithmFactor() : 0; } else if (PoolClass == PoolServiceClass.SingleCoinPool) { IOnlineServiceEntry entry = ScriptManager.Context.OnlineService.GetEntry(ServiceType, Port); return (entry != null) ? entry.BtcPerNormalizedMhsPerDay * GetAlgorithmFactor() : 0; } else return ScriptManager.Context.Pool.GetPoolRevenuePerDay(Pool, true) * GetAlgorithmFactor(); } public bool IsValid() { return Pool != null && (PoolClass != PoolServiceClass.MultiCoinPool || ScriptManager.Context.OnlineService.GetEntry(ServiceType, Algorithm) != null); } private double GetAlgorithmFactor() { if (algorithmFactor.ContainsKey(Algorithm)) return algorithmFactor[Algorithm]; else return 1; } }