Every mining calculator uses the same formula. Your hashrate over the network hashrate, times blocks per day, times the block reward. On Ergo it was overstating daily revenue by 75%. The arithmetic is correct, the inputs are real, and nothing in the code looks wrong. That is what makes it worth writing down.
coins_per_day = (my_hashrate / network_hashrate) * blocks_per_day * block_reward
It needs three numbers off the chain. Network hashrate, block time, block reward.
Two of those carry per-chain unit conventions that nobody agrees on.
And it invites one specific mistake, which is the subject of this article.
Ergo, measured in one sitting.
| Source | Value |
|---|---|
| node difficulty divided by the 120 s target | 546.8 GH/s |
| realized, from 199 real block headers | 312.1 GH/s |
| the explorer's own /info hashRate | 440.4 GH/s |
Three answers spread over 1.75 times, for one chain, at one moment.
They disagree because the realized block time over those 199 blocks was 210.2 seconds, not the 120 the chain aims for. Ergo's retarget lags on a chain whose hashrate is falling, so difficulty is set for a network that has already gone.
None of those three numbers is a lie. They measure different things.
Take an RTX 5080 at 294 MH/s and compute it three ways.
| Inputs | Result |
|---|---|
| difficulty form, no block time | 1.161 ERG/day |
| matched pair: 546.8 GH/s and 720 blocks/day | 1.161 ERG/day |
| mixed pair: realized 312.1 GH/s and 720 blocks/day | 2.03 ERG/day |
The third one is 75% too high.
And it is the natural thing to build. You take the hashrate from the explorer, because the explorer measures reality. You take blocks per day from the spec sheet, because that is the chain's stated block time.
One measures what is happening. The other measures what is intended. Multiply them together and the mismatch becomes revenue.
coins_per_day = (my_hashrate_H_per_s * 86400 / D) * block_reward
D is the expected number of hashes needed to find one block, counted in the same hash your miner counts.
The derivation is short. A miner runs independent trials. Each succeeds with probability p equal to the target over 2^256. Define D as 1 over p. Over 86400 seconds you get h times 86400 trials, so the expected blocks found is that divided by D. Multiply by the reward.
Block time never enters it. How often the whole network finds a block is not a term in the question of how often you find one.
The two correct rows in the table above are algebraically the same as this. Network hashrate is D over T, and blocks per day is 86400 over T, so T cancels. The mixed pair breaks that cancellation by using two different values of T without noticing.
So the rule is not "be careful pairing your inputs". It is simpler. Never let network hashrate into the arithmetic. Display it if you like. Compute with D.
Now the second trap. You need D, and every chain hands you a field called difficulty.
They do not mean the same thing by it.
Difficulty is a presentation field. Each project picked a divisor when it wrote its RPC layer. The target is not a presentation field. It is consensus, it is in the block header, and D equals 2^256 over target plus one, everywhere, always.
Here is Ravencoin proved from one block header and nothing else. Bits are 0x1b06e29a, and the reported difficulty is 9518.294069933914.
exponent = 0x1b = 27, mantissa = 0x06e29a = 451226
target = 451226 << 8*(27-3) = 2.83239e63
D = 2^256 / (target+1) = 4.08814e13
D / difficulty = 4.29503e9
2^32 = 4.29497e9 ratio 1.000015
So Ravencoin's difficulty is Bitcoin relative, and the multiplier is 2^32. That was derived without trusting anyone.
Kaspa is a different number. Its daemon defines difficulty as 2^255 minus 1, over target. That is half the expected hash count, so the multiplier is 2, not 2^32 and not 1.
Assume Bitcoin's convention there and you are wrong by 2.1 billion times. Assume the multiplier is 1 and you are wrong by exactly 2, which is far more dangerous because it looks survivable.
| Multiplier on reported difficulty | Convention | Seen on |
|---|---|---|
| 2^32 | Bitcoin relative | Ravencoin, Raptoreum, Firo, Vertcoin, Decred, Zcash family |
| 1 | difficulty already is D | Ergo, Monero, Ethash family, Alephium, Iron Fish, Conflux |
| 2 | kaspad's 2^255 over target | Kaspa, Karlsen, Pyrin, Hoosat, Nexellia, Astrix, Cryptix |
| none | difficulty counts solutions, not hashes | Equihash and Cuckoo Cycle coins |
That last row is the one to be frightened of. On Equihash and Cuckoo Cycle chains, a solution is not a hash, so there is no multiplier that makes the equation work. If you cannot prove the unit for a coin, publish no revenue for it. An honest gap is worth more than a confident wrong number.
This also explains why pool APIs look inconsistent. A pool reporting Ravencoin difficulty around 9393 and Alephium difficulty around 2.6e15 is not confused. It is faithfully passing through two daemons that use different conventions. A pool API is a good cross-check and a bad source of truth.
One more, quickly, because it fails the same silent way.
Do not hardcode the emission schedule. Halvings, soft forks and treasury splits all move the number, and a hardcoded constant stays confidently wrong for months after the chain changed.
Read the coinbase transaction of a recent block and take the actual value paid. It is the one number that cannot drift out of date.