I’ve decided to update this pseudocode for Atlas-
NO_attestations = 0
reth_attestations = 0
minipool_attestations = {}
for each minipool:
for each attestation:
// Only include attestations that could have increased SP balance via proposal
if attestation.missed() or not minipool.inSmoothingPoolForSlot(attestation) or not minipool.active():
continue
let bond = minipool.bond/32
let minipool_score = bond + (minipool.commission)(1-minipool.bond)
// Increase the total pseudo-attestation count owed to NOs
NO_attestations += minipool_score
// Increase the total pseudo-attestation count owed to rETH
reth_attestations += 1-minipool_score
// Increase this minipool's pseudo-attestation performance
minipool_attestations[minipool] += minipool_score
let node_rewards = {}
// rETH gets its share
let totalRETHSmoothingPoolBalance = totalSmoothingPoolBalance * (reth_attestations / (reth_attestations + NO_attestations))
// NOs get the rest
let totalNOSmoothingPoolBalance = totalSmoothingPoolBalance - totalRETHSmoothingPoolBalance
for each minipool:
// Each minipool gets its weighted attestation amount divided by the total NO weighted attestations, aggregated per node
node_rewards[minipool.node] += totalNOSmoothingPoolBalance * minipool_attestations[minipool] / NO_attestations
Critically, this is fair because
minipool_score + (1-minipool_score)
evaluates to 1 (the atomic attestation), and minipool.bond/32 + (minipool.commission)(1-minipool.bond)
evaluates to the percentage of the rewards for that attestation that are owed to the node operator… e.g., a LEB8 with 14% commission:
0.25 + (0.14)(0.75)
Or a 16e minipool with 15% commission:
0.5 + (0.15)(0.5)