# Block Reward Halving Schedule **Published by:** [Bitcoinu](https://paragraph.com/@bitcoinu/) **Published on:** 2025-03-19 **URL:** https://paragraph.com/@bitcoinu/block-reward-halving-schedule ## Content ScheduleThe mining rewards for Bitcoinu are distributed to the winner of each block, with one block consisting of four days. The reward for each block is predetermined and allocated accordingly. The block rewards halve every 91 blocks (= 364 days), and all 21 million Bitcoinu will be mined within five years. The details are as follows:In the fifth year, the block rewards remain the same as in the fourth year without further halving, ensuring that a total of 21 million Bitcoinu is mined over the five-year period. The distribution ratio of the total mining volume is as follows:Why Complete Mining in Five Years?Bitcoin follows a four-year halving schedule, extending the mining process over more than 100 years to reach the total supply of 21 million coins. In comparison, Bitcoinu has an annual halving schedule and completes mining within five years, making it a significantly shorter process. There are two main reasons for this:Rapid Awareness Expansion Unlike Bitcoin’s PoW mining, which contributes to security through cryptographic calculations, Bitcoinu’s mining rewards are earned by contributing to awareness expansion through posts on X. This allows for much faster recognition growth than Bitcoin, ensuring a sufficiently distributed allocation even within a shorter timeframe.Early Elimination of Dependency on X and Operations Since Bitcoinu mining depends on X and its operational system, there are inherent, albeit minimized, centralized risks (such as impression manipulation on X or system errors in operations). The goal is to eliminate these dependencies as early as possible and transition to a fully decentralized asset.Time DeterminationThe block number is determined based on the timestamp of the Ethereum mainnet. While the actual mining takes place on Base, a Layer 2 network, the timestamps from the mainnet (L1) are referenced and used. This approach is adopted because Ethereum mainnet timestamps are verified by decentralized validators, making them highly secure and resistant to manipulation. Below is the smart contract that transmits timestamps from the mainnet to Base.// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@base-org/contracts/contracts/BridgeAdapter.sol"; /** * @title BlockTimeOracle * @dev A contract that sends block time from the Ethereum mainnet to the Base Layer 2. * Implements a two-tier permission management system (Admin, SuperAdmin). */ contract BlockTimeOracle { // Address of the target contract on the Base network address public baseReceiverAddress; // Instance of the Base Bridge Adapter BridgeAdapter public bridgeAdapter; // Addresses for permission management address public admin; address public superAdmin; // Modifiers modifier onlyAdmin() { require(msg.sender == admin, "Caller is not the admin"); _; } modifier onlySuperAdmin() { require(msg.sender == superAdmin, "Caller is not the super admin"); _; } /** * @dev Constructor * @param _bridgeAdapterAddress Address of the Base Bridge Adapter * @param _baseReceiverAddress Address of the receiver contract on the Base network * @param _admin Initial Admin * @param _superAdmin Initial SuperAdmin */ constructor( address _bridgeAdapterAddress, address _baseReceiverAddress, address _admin, address _superAdmin ) { bridgeAdapter = BridgeAdapter(_bridgeAdapterAddress); baseReceiverAddress = _baseReceiverAddress; admin = _admin; superAdmin = _superAdmin; } /** * @dev Sends the current block time to Base. * Can be called by anyone. */ function sendBlockTimeToBase() external { // Get the current block time uint256 currentBlockTime = block.timestamp; // Prepare function signature and parameters to call the contract on Base bytes memory callData = abi.encodeWithSignature( "receiveBlockTime(uint256)", currentBlockTime ); // Send the message via the Base Bridge bridgeAdapter.send(baseReceiverAddress, callData); // Emit an event emit BlockTimeSent(currentBlockTime); } /** * @dev Updates the Base receiver address (Requires Admin permission). * @param _baseReceiverAddress New Base receiver address */ function updateReceiverAddress(address _baseReceiverAddress) external onlyAdmin { baseReceiverAddress = _baseReceiverAddress; emit ReceiverAddressUpdated(_baseReceiverAddress); } /** * @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); } // Events event BlockTimeSent(uint256 blockTime); event ReceiverAddressUpdated(address baseReceiverAddress); event AdminChanged(address oldAdmin, address newAdmin); event SuperAdminChanged(address oldSuperAdmin, address newSuperAdmin); } The smart contract that receives on Base is as follows.// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title BlockTimeReceiver * @dev A contract on Base Layer 2 that receives and stores block time from the Ethereum mainnet. * A simplified version that retains only the latest block time. * Implements a two-tier permission management system (Admin, SuperAdmin). */ contract BlockTimeReceiver { // Address of the oracle contract on the Ethereum mainnet address public mainnetOracleAddress; // Last received block time uint256 public lastReceivedBlockTime; // Addresses for permission management address public admin; address public superAdmin; // Modifiers modifier onlyAdmin() { require(msg.sender == admin, "Caller is not the admin"); _; } modifier onlySuperAdmin() { require(msg.sender == superAdmin, "Caller is not the super admin"); _; } /** * @dev Constructor * @param _mainnetOracleAddress Address of the oracle on the Ethereum mainnet * @param _admin Initial Admin * @param _superAdmin Initial SuperAdmin */ constructor( address _mainnetOracleAddress, address _admin, address _superAdmin ) { mainnetOracleAddress = _mainnetOracleAddress; admin = _admin; superAdmin = _superAdmin; lastReceivedBlockTime = 0; } /** * @dev Function to receive block time from the mainnet * @param _blockTime Received block time */ function receiveBlockTime(uint256 _blockTime) external { // Ensure the sender is the oracle contract on the mainnet // Messages from the Base Bridge are sent by specific relayers // In actual implementation, it must follow the Base Bridge message authentication system require( _isValidRelayer(msg.sender), "Caller is not an authorized relayer" ); // Ensure the new block time is greater than the previous one require( _blockTime > lastReceivedBlockTime, "New block time must be greater than the last one" ); // Update the block time lastReceivedBlockTime = _blockTime; // Emit an event emit BlockTimeReceived(_blockTime); } /** * @dev Internal function to verify whether the sender is a valid relayer * Only allows the alias address of the oracle contract on the mainnet */ function _isValidRelayer(address _sender) internal view returns (bool) { // Compute the L2 alias address of the mainnet oracle contract address expectedSender = _getL2AliasOfL1ContractAddress(mainnetOracleAddress); // Check if the sender matches the alias address return _sender == expectedSender; } /** * @dev Computes the alias address of an L1 contract on L2 * @param _l1Address L1 contract address * @return Alias address on L2 */ function _getL2AliasOfL1ContractAddress(address _l1Address) internal pure returns (address) { // Implements OP Stack's address aliasing rules // Replaces the upper 20 bits of the L1 address with 0x1111... (Optimism's reserved prefix) return address( uint160( uint160(0x1111000000000000000000000000000000001111) | (uint160(_l1Address) & uint160(0x00ffffffffffffffffffffffffffffffffffffffff)) ) ); } /** * @dev Function to retrieve the last received block time (read-only) */ function getLatestBlockTime() external view returns (uint256) { return lastReceivedBlockTime; } /** * @dev Updates the mainnet oracle address (Requires Admin permission). * @param _mainnetOracleAddress New mainnet oracle address */ function updateOracleAddress(address _mainnetOracleAddress) external onlyAdmin { mainnetOracleAddress = _mainnetOracleAddress; emit OracleAddressUpdated(_mainnetOracleAddress); } /** * @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); } // Events event BlockTimeReceived(uint256 blockTime); event OracleAddressUpdated(address mainnetOracleAddress); event AdminChanged(address oldAdmin, address newAdmin); event SuperAdminChanged(address oldSuperAdmin, address newSuperAdmin); } Mining Smart ContractUsing the aforementioned time, the mining contract implements the following two functions:Block UnlockingBased on the mainnet time above, the contract unlocks blocks that are eligible for mining. Additionally, blocks that have passed 10 blocks in time will be locked, making them unavailable for mining.MiningUsers can obtain a permitted amount of BTCu from mineable blocks 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); } } ## Publication Information - [Bitcoinu](https://paragraph.com/@bitcoinu/): Publication homepage - [All Posts](https://paragraph.com/@bitcoinu/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@bitcoinu): Subscribe to updates