Winners receive block rewards based on the impressions of the posts they submitted.
Specifically, points are calculated using the following formula, and block rewards are distributed proportionally based on these points:
First, to prevent mining by a large number of bot accounts, impressions below 50 are assigned a point value of 0.
Next, to prevent excessive concentration of rewards on influencers and promote decentralization, points are determined as the square root of impressions. This means that even if impressions increase by a factor of 100, the reward only increases by a factor of 10.

Furthermore, if impressions exceed 1,000,000, the point value is capped at 1000. For example, if a typical post receives 100 impressions, its point value would be 10, meaning that even in the maximum case, a single viral post would receive no more than approximately 100 times the reward of a typical post. This mechanism prevents a single viral post from monopolizing most of the block rewards.

There is no difference in point calculation between verified and unverified winners.
In proportional distribution, amounts below 1 satoshi are truncated. The resulting remainder is allocated to the winner with the highest impressions. (If multiple winners have the same number of impressions, priority is given to the earliest verified user to apply.)
/**
* Function to calculate points from impressions
* @param {number} impression - Number of impressions
* @return {number} - Calculated points
*/
function calculatePoints(impression) {
// If 50 or below, points are 0
if (impression <= 50) {
return 0;
}
// If 1,000,000 or more, calculate as 1,000,000
const cappedImpression = Math.min(impression, 1000000);
// Points are determined as the square root of impressions
return Math.sqrt(cappedImpression);
}
/**
* Function to add points to the list of winners
* @param {Array<Object>} winnersList - List of winners
* @return {Array<Object>} - List of winners with added points
*/
function addPointsToWinners(winnersList) {
return winnersList.map(winner => {
// Create a new object without modifying the existing one
return {
...winner,
point: calculatePoints(winner.impression)
};
});
}
// Export for Node.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
calculatePoints,
addPointsToWinners
};
}
/**
* Function to distribute Bitcoin rewards to winners in proportion to their points
* @param {Array<Object>} winnersWithPoints - List of winners with added points
* @param {number} blockReward - Total reward to be distributed (in satoshis)
* @return {Array<Object>} - List of winners with added rewards
*/
function distributeReward(winnersWithPoints, blockReward) {
// Calculate total points
const totalPoints = winnersWithPoints.reduce((sum, winner) => sum + winner.point, 0);
// If total points are zero, do not distribute rewards
if (totalPoints === 0) {
return winnersWithPoints.map(winner => ({
...winner,
reward: 0
}));
}
// Calculate initial distribution (truncated)
const winnersWithReward = winnersWithPoints.map(winner => {
const rewardAmount = Math.floor((winner.point / totalPoints) * blockReward);
return {
...winner,
reward: rewardAmount
};
});
// Calculate the total amount of the initial distribution
const distributedReward = winnersWithReward.reduce((sum, winner) => sum + winner.reward, 0);
// Remaining reward (unallocated fraction)
const remainingReward = blockReward - distributedReward;
// If there is remaining reward, allocate it to the winner with the highest impressions
if (remainingReward > 0) {
// Find the index of the winner with the highest impressions
let maxImpressionIndex = 0;
let maxImpression = winnersWithReward[0].impression;
for (let i = 1; i < winnersWithReward.length; i++) {
if (winnersWithReward[i].impression > maxImpression) {
maxImpression = winnersWithReward[i].impression;
maxImpressionIndex = i;
}
}
// Allocate all remaining rewards to the winner with the highest impressions
winnersWithReward[maxImpressionIndex].reward += remainingReward;
}
return winnersWithReward;
}
/**
* Function to merge the lists of verified and unverified winners and distribute rewards
* @param {Array<Object>} verifiedWinners - List of verified winners
* @param {Array<Object>} unverifiedWinners - List of unverified winners
* @param {number} blockReward - Total reward to be distributed (in satoshis)
* @return {Array<Object>} - List of winners with distributed rewards
*/
function mergeAndDistributeReward(verifiedWinners, unverifiedWinners, blockReward) {
// Merge both lists
const allWinners = [...verifiedWinners, ...unverifiedWinners];
// Calculate points
const winnersWithPoints = addPointsToWinners(allWinners);
// Distribute rewards
const winnersWithReward = distributeReward(winnersWithPoints, blockReward);
return winnersWithReward;
}
// Export for Node.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
calculatePoints,
addPointsToWinners,
distributeReward,
mergeAndDistributeReward
};
}
// Export to global scope for use in Cloudflare Workers
if (typeof self !== 'undefined') {
self.calculatePoints = calculatePoints;
self.addPointsToWinners = addPointsToWinners;
self.distributeReward = distributeReward;
self.mergeAndDistributeReward = mergeAndDistributeReward;
}

