
ビットコインのマイニングが不公平である理由と量子コンピュータ問題
ビットコインは総発行量の25%は5-10人程度によって採掘されている。ビットコインは最初の2年間(2009-2010年)で総発行量2100万枚の25%、つまり525万枚が採掘されています。この525万枚のBTCは何人によって採掘されたのでしょうか? もちろん、正確な数字は分かりません。1人が多数の採掘アドレスを使っているからです。 しかし、開発者のサトシ・ナカモトがこの2年間で110万枚、つまり当時の採掘量の1/5を彼1人で採掘していると推定されています。 当時はCPU、つまり一般的な家庭用PCでマイニングしていた時代ですから、サトシも例外ではなかったはずです。つまり、他のマイナーもサトシ同様の計算力で同期間マイニングしていたとすると、サトシを含めてたったの5人しかいなかったことになります。 実際には、サトシは最初から最も長く採掘していたと考えられるので、他の参加者は遅れて参加しているからもう少し採掘量は少なかったと考えると、人数はもう少し増えるでしょう。 それでも、25%の大半は5-10人くらいに初期分配されたと考えるのが自然なのです。 恐らく、ビットコインの開発に関わった少人...

マイニングの参加条件
参加条件ビットコいぬのマイニングは、ブロック(4日)ごとにXでポストした参加者を募集し、抽選によって選ばれた当選者に新規発行されたBTCuが割り当てられます。 抽選アルゴリズムと割り当てのルールについては他の記事で説明していますが、ここでは参加するために満たすべき最低条件を説明します。 ビットコいぬのマイニングに応募するためには、以下の条件を満たす必要があります。 抽選後に当選者についてのみ確認が行われます。 これらの参加条件を1つでも満たしていないと、当選しても割り当ては0になります。1ブロックにつき、1アカウント1つのポストを応募できる。応募できるポストは応募者本人のアカウントが投稿したポストに限られる。保護された非公開アカウントではなく、公開されているアカウントであること。非承認アカウントは開設から1年以上経過していなくてはならない。(承認アカウントはこの制約はない)参加したブロックの期間中に投稿されたポストであること。参加したブロックの終了時点から3日後までポストが削除されていないこと。参加したブロックの終了時点から3日後にインプレッションが50以上あること。ハッシュタグ...

ビットコインの発行上限2100万枚は維持できず、崩壊するという話
発行上限という神話の崩壊「ビットコインの総発行量は2100万枚で固定されていて、誰もこれを変更することはできない」 この仕様はビットコインがデジタルゴールドと呼ばれる様になった理由であり、ビットコインというブランド価値の中核といえます。 しかし、誰もが信じるこの仕様は、実は保証されているものではありません。 それどころか、この仕様のせいでビットコインは崩壊するリスクさえあるのです。BTCの新規発行は、セキュリティコストの大部分を占めているあらゆるブロックチェーンのセキュリティは、以下2つの財源によって守られています。 ①コインの新規発行 ②取引手数料 ビットコインは新規発行を半減期によって減少させてゆき、最終的には0にして2100万枚の供給量に固定するプログラムになってます。 つまり、最終的には取引手数料だけで、セキュリティ維持に必要な財源を賄うという計画なのです。 しかし現在、取引手数料は全体のわずか1%程度に過ぎないのです。 セキュリティはほとんどが新規発行によって維持されているのです。 このまま取引手数料が大きく増えなければ、半減期によってセキュリティはどんどん減少してゆく...



ビットコインのマイニングが不公平である理由と量子コンピュータ問題
ビットコインは総発行量の25%は5-10人程度によって採掘されている。ビットコインは最初の2年間(2009-2010年)で総発行量2100万枚の25%、つまり525万枚が採掘されています。この525万枚のBTCは何人によって採掘されたのでしょうか? もちろん、正確な数字は分かりません。1人が多数の採掘アドレスを使っているからです。 しかし、開発者のサトシ・ナカモトがこの2年間で110万枚、つまり当時の採掘量の1/5を彼1人で採掘していると推定されています。 当時はCPU、つまり一般的な家庭用PCでマイニングしていた時代ですから、サトシも例外ではなかったはずです。つまり、他のマイナーもサトシ同様の計算力で同期間マイニングしていたとすると、サトシを含めてたったの5人しかいなかったことになります。 実際には、サトシは最初から最も長く採掘していたと考えられるので、他の参加者は遅れて参加しているからもう少し採掘量は少なかったと考えると、人数はもう少し増えるでしょう。 それでも、25%の大半は5-10人くらいに初期分配されたと考えるのが自然なのです。 恐らく、ビットコインの開発に関わった少人...

マイニングの参加条件
参加条件ビットコいぬのマイニングは、ブロック(4日)ごとにXでポストした参加者を募集し、抽選によって選ばれた当選者に新規発行されたBTCuが割り当てられます。 抽選アルゴリズムと割り当てのルールについては他の記事で説明していますが、ここでは参加するために満たすべき最低条件を説明します。 ビットコいぬのマイニングに応募するためには、以下の条件を満たす必要があります。 抽選後に当選者についてのみ確認が行われます。 これらの参加条件を1つでも満たしていないと、当選しても割り当ては0になります。1ブロックにつき、1アカウント1つのポストを応募できる。応募できるポストは応募者本人のアカウントが投稿したポストに限られる。保護された非公開アカウントではなく、公開されているアカウントであること。非承認アカウントは開設から1年以上経過していなくてはならない。(承認アカウントはこの制約はない)参加したブロックの期間中に投稿されたポストであること。参加したブロックの終了時点から3日後までポストが削除されていないこと。参加したブロックの終了時点から3日後にインプレッションが50以上あること。ハッシュタグ...

ビットコインの発行上限2100万枚は維持できず、崩壊するという話
発行上限という神話の崩壊「ビットコインの総発行量は2100万枚で固定されていて、誰もこれを変更することはできない」 この仕様はビットコインがデジタルゴールドと呼ばれる様になった理由であり、ビットコインというブランド価値の中核といえます。 しかし、誰もが信じるこの仕様は、実は保証されているものではありません。 それどころか、この仕様のせいでビットコインは崩壊するリスクさえあるのです。BTCの新規発行は、セキュリティコストの大部分を占めているあらゆるブロックチェーンのセキュリティは、以下2つの財源によって守られています。 ①コインの新規発行 ②取引手数料 ビットコインは新規発行を半減期によって減少させてゆき、最終的には0にして2100万枚の供給量に固定するプログラムになってます。 つまり、最終的には取引手数料だけで、セキュリティ維持に必要な財源を賄うという計画なのです。 しかし現在、取引手数料は全体のわずか1%程度に過ぎないのです。 セキュリティはほとんどが新規発行によって維持されているのです。 このまま取引手数料が大きく増えなければ、半減期によってセキュリティはどんどん減少してゆく...

Subscribe to Bitcoinu

Subscribe to Bitcoinu
<100 subscribers
<100 subscribers
The 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:

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.
The 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.
The smart contract that receives on Base is as follows.
Using 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.
The 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:

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.
The 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.
The smart contract that receives on Base is as follows.
Using 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
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);
}
// SPDX-License-Identifier: MIT
/**
* @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);
}
// SPDX-License-Identifier: MIT
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);
}
}
// SPDX-License-Identifier: MIT
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);
}
// SPDX-License-Identifier: MIT
/**
* @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);
}
// SPDX-License-Identifier: MIT
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);
}
}
Share Dialog
Share Dialog
No activity yet