The mining of Bitcoinu follows the process below for each block:
Block Period: Post Recruitment
End of Block: Application Deadline and Public Release of Submitted Posts
Three Days Later: Announcement of Winners
10 Blocks Later: Deadline for Claiming Mining Rewards

To participate in mining a specific block, you must post a qualifying post (X post) during the block’s period (4 days) and enter the URL of the post in the site’s application form.
Note: Verified accounts are given priority in winning chances. For more details, click here.
Any applications submitted after the block’s end will be invalid.
Within minutes after the block’s end, a list of all submitted posts will be made public, and their hashes will be recorded on the Base chain. (This ensures that the submitted posts are fixed and cannot be manipulated, including by the administrators.)
3 days after the block’s end, the winners will be selected using an algorithm based on the blockhash at that time and will be publicly announced.
After this, the winners can claim the BTCu rewards distributed according to the impressions from the Block Rewards on the site.
Once the winner of the block, 10 blocks after the original block, is announced, the claim for the mining reward will no longer be possible.
Therefore, if you win, you must claim your mining rewards within 10 blocks (40 days).
The smart contract for mining is as follows:
Block Unlock
3 days after the end of the block, the block eligible for mining will be unlocked. Blocks that have passed 10 blocks will be locked and cannot be mined.Mining
Users can obtain BTCu from blocks eligible for mining, up to the amount permitted by the administrator, with the administrator’s signature.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
interface IBlockTimeReceiver {
function getLatestBlockTime() external view returns (uint256);
}
/**
* @title BitcoinuBlockRewardManager
* @dev A contract on the Base blockchain that manages the 4-day block-based release of Bitcoinu tokens.
*/
contract BitcoinuBlockRewardManager {
using ECDSA for bytes32;
// Enumeration representing the status of a block
enum BlockStatus {
Inactive, // Not unlocked
Active, // Unlocked and available for mining
Locked // Locked and unavailable for mining (older than 10 blocks)
}
// Structure to store block information
struct BlockInfo {
uint256 totalReleaseAmount; // Total release amount for the block (in satoshi)
uint256 releasedAmount; // Amount already released (in satoshi)
uint256 endTime; // Block end time (timestamp)
BlockStatus status; // Status of the block
}
// Constants
uint256 public constant BLOCK_DURATION = 4 days; // Block duration in seconds - 4 days = 345,600 seconds
// Immutable variables (set only in the constructor)
IBlockTimeReceiver public immutable blockTimeReceiver; // BlockTimeReceiver contract
IERC20 public immutable bitcoinuToken; // Bitcoinu token contract
uint256 public immutable startTimestamp; // Timestamp at the start
// State variables
address public admin; // Admin address
address public superAdmin; // Super admin address
BlockInfo[] public blocks; // Array storing block information
uint256[] public blockReleaseAmounts; // Table of release amounts per block number (in satoshi)
// Mapping: user ID => mined block number => whether already mined
mapping(uint256 => mapping(uint256 => bool)) public userMinedBlocks;
// Modifiers
modifier onlyAdmin() {
require(msg.sender == admin, "Caller is not an admin");
_;
}
modifier onlySuperAdmin() {
require(msg.sender == superAdmin, "Caller is not a super admin");
_;
}
// Event definitions
event BlockUnlocked(uint256 indexed blockNumber, uint256 amount);
event BlocksMined(uint256 indexed blockNumber, uint256 userId, address userAddress, uint256 amount);
event BlocksLocked(uint256 fromBlock, uint256 toBlock);
event AdminChanged(address oldAdmin, address newAdmin);
event SuperAdminChanged(address oldSuperAdmin, address newSuperAdmin);
/**
* @dev Constructor
* @param _blockTimeReceiver Address of the BlockTimeReceiver contract
* @param _bitcoinuToken Address of the Bitcoinu token
* @param _admin Admin address
* @param _superAdmin Super admin address
*/
constructor(
address _blockTimeReceiver,
address _bitcoinuToken,
address _admin,
address _superAdmin
) {
require(_admin != address(0), "Admin cannot be zero address");
require(_superAdmin != address(0), "SuperAdmin cannot be zero address");
blockTimeReceiver = IBlockTimeReceiver(_blockTimeReceiver);
bitcoinuToken = IERC20(_bitcoinuToken);
admin = _admin;
superAdmin = _superAdmin;
// Set the start timestamp to the current block time
startTimestamp = blockTimeReceiver.getLatestBlockTime();
// Define release amounts for each block range (in satoshi)
blockReleaseAmounts.push(11538461538461); // Blocks 0-90
blockReleaseAmounts.push(5769230769231); // Blocks 91-181
blockReleaseAmounts.push(2884615384615); // Blocks 182-272
blockReleaseAmounts.push(1442307692308); // Blocks 273-363
blockReleaseAmounts.push(1442307692308); // Blocks 364-454
}
// === Read-Only Functions (view/pure) ===
/**
* @dev Retrieves the current block number.
* @return The current block number.
*/
function getCurrentBlockNumber() public view returns (uint256) {
uint256 currentTime = blockTimeReceiver.getLatestBlockTime();
if (currentTime <= startTimestamp) {
return 0;
}
uint256 elapsedTime = currentTime - startTimestamp;
return elapsedTime / BLOCK_DURATION;
}
/**
* @dev Retrieves the release amount for a given block number.
* @param blockNumber The block number.
* @return The release amount (in satoshi).
*/
function getReleaseAmountForBlock(uint256 blockNumber) public view returns (uint256) {
if (blockNumber <= 90) {
return blockReleaseAmounts[0];
} else if (blockNumber <= 181) {
return blockReleaseAmounts[1];
} else if (blockNumber <= 272) {
return blockReleaseAmounts[2];
} else if (blockNumber <= 363) {
return blockReleaseAmounts[3];
} else if (blockNumber <= 454) {
return blockReleaseAmounts[4];
} else {
return 0; // No release after block 455
}
}
/**
* @dev Retrieves the total number of blocks created so far.
* @return The length of the block array.
*/
function getBlockCount() public view returns (uint256) {
return blocks.length;
}
/**
* @dev Retrieves all block information at once.
* @return An array of block information.
*/
function getAllBlocks() external view returns (BlockInfo[] memory) {
BlockInfo[] memory result = new BlockInfoUnsupported embed;
for (uint256 i = 0; i < blocks.length; i++) {
result[i] = blocks[i];
}
return result;
}
// === State-Changing Functions ===
/**
* @dev Unlocks a block (Requires Admin permission).
* @param blockNumber The block number to unlock.
*/
function unlock(uint256 blockNumber) external onlyAdmin {
require(blockNumber <= getCurrentBlockNumber(), "Block not reached yet");
// Calculate the release amount
uint256 releaseAmount = getReleaseAmountForBlock(blockNumber);
require(releaseAmount > 0, "No tokens to release for this block");
// Calculate the block end time
uint256 blockEndTime = startTimestamp + ((blockNumber + 1) * BLOCK_DURATION);
// Expand the block array if necessary
while (blocks.length <= blockNumber) {
blocks.push(BlockInfo(0, 0, 0, BlockStatus.Inactive));
}
require(blocks[blockNumber].status == BlockStatus.Inactive, "Block already unlocked or locked");
// Update block information
blocks[blockNumber].totalReleaseAmount = releaseAmount;
blocks[blockNumber].endTime = blockEndTime;
blocks[blockNumber].status = BlockStatus.Active;
// Lock blocks older than 10 blocks
if (blockNumber >= 10) {
uint256 lockFromBlock = blockNumber - 10;
// Lock only lockFromBlock (earlier blocks should already be locked)
if (blocks[lockFromBlock].status == BlockStatus.Active) {
blocks[lockFromBlock].status = BlockStatus.Locked;
emit BlocksLocked(lockFromBlock, lockFromBlock);
}
}
emit BlockUnlocked(blockNumber, releaseAmount);
}
// === Administrative Functions ===
/**
* @dev Changes the Admin (Requires SuperAdmin permission).
* @param _newAdmin New Admin.
*/
function changeAdmin(address _newAdmin) external onlySuperAdmin {
require(_newAdmin != address(0), "New admin cannot be zero address");
address oldAdmin = admin;
admin = _newAdmin;
emit AdminChanged(oldAdmin, _newAdmin);
}
/**
* @dev Changes the SuperAdmin (Requires current SuperAdmin permission).
* @param _newSuperAdmin New SuperAdmin.
*/
function changeSuperAdmin(address _newSuperAdmin) external onlySuperAdmin {
require(_newSuperAdmin != address(0), "New super admin cannot be zero address");
address oldSuperAdmin = superAdmin;
superAdmin = _newSuperAdmin;
emit SuperAdminChanged(oldSuperAdmin, _newSuperAdmin);
}
}

