A 2017 conceptual token by Constantine Nicholas using block.difficulty as the price variable; bricked post-merge by prevrandao.
Historical Significance
A 2017 conceptual on-chain art piece that became unintentionally bricked by The Merge. Paired with BHI (block.number variant) which still works.
Context
Deployed Feb 20, 2017 — five years before The Merge. The author had no way to predict that block.difficulty would later return a 250-bit random number, but the buy() math depends on block.difficulty being a small uint, so the contract effectively died on Sept 15, 2022.
Token Information
Key Facts
Description
Block Difficulty Index (BDI) is the sister contract to BHI, deployed Feb 20, 2017 by Constantine Nicholas. It uses block.difficulty in place of block.number as the price-determining variable. The bytecode differs from BHI by exactly 4 bytes (two NUMBER opcodes replaced by DIFFICULTY) inside buy().
A fixed Fee fraction (default 1/100) of every buy, sell, transfer, and transferFrom is skimmed to the contract owner. The Transfer event has six fields (from, to, amount, fee_amount, lastBuyPrice, lastSellPrice), not the standard three.
Bricked post-merge: after The Merge (Sept 2022), block.difficulty returns prevrandao (~2^250). The buy formula amount = msg.value * 10^18 / block.difficulty / Fee evaluates to 0 for any sane msg.value, triggering the if (amount == 0) throw guard. buy() reverts with "invalid jump destination" for every call.
Source Verified
Source reconstruction. Sister contract to BHI; only difference is block.number -> block.difficulty (2 opcodes). Bricked post-merge by prevrandao.. Optimizer: ON (200 runs)
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Spurious Dragon Era
Continued DoS protection. State trie clearing.
Bytecode Overview
Verified Source Available
This contract has verified source code.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
pragma solidity ^0.4.0;
contract owned {
address public owner;
function owned() {
owner = msg.sender;
}
modifier onlyOwner {
if (msg.sender != owner) throw;
_;
}
function transferOwnership(address newOwner) onlyOwner {
owner = newOwner;
}
}
contract tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); }
contract BlockDifficultyIndex is owned {
string public name = "Constantine Nicholas: Block Difficulty Index";
string public symbol = "BDI";
uint8 public decimals = 18;
uint256 public totalSupply;
uint256 public Fee = 100;
uint256 public lastBuyPrice;
uint256 public lastSellPrice;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
event Transfer(address from, address to, uint256 a, uint256 b, uint256 c, uint256 d);
event Buy(address from, address to, uint256 a, uint256 b, uint256 c, uint256 d);
event Sell(address from, address to, uint256 a, uint256 b, uint256 c, uint256 d);
function BlockDifficultyIndex(uint256 initialSupply) {
balanceOf[msg.sender] = initialSupply;
totalSupply = initialSupply;
}
function transfer(address _to, uint256 _value) {
if (balanceOf[msg.sender] < _value) throw;
if (balanceOf[_to] + _value < balanceOf[_to]) throw;
uint feeAmount = _value / Fee;
if (feeAmount == 0) throw;
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value - feeAmount;
balanceOf[owner] += feeAmount;
Transfer(msg.sender, _to, _value, feeAmount, lastBuyPrice, lastSellPrice);
}
function approve(address _spender, uint256 _value) returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
returns (bool success) {
allowance[msg.sender][_spender] = _value;
tokenRecipient(_spender).receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
if (balanceOf[_from] < _value) throw;
if (balanceOf[_to] + _value < balanceOf[_to]) throw;
if (_value > allowance[_from][msg.sender]) throw;
uint feeAmount = _value / Fee;
if (feeAmount == 0) throw;
balanceOf[_from] -= _value;
balanceOf[_to] += _value - feeAmount;
balanceOf[owner] += feeAmount;
allowance[_from][msg.sender] -= _value;
Transfer(_from, _to, _value, feeAmount, lastBuyPrice, lastSellPrice);
return true;
}
function changeFee(uint256 _newFee) onlyOwner {
if (_newFee < 100) throw;
Fee = _newFee;
}
function buy() payable {
uint amount = 10**18 * msg.value / block.difficulty;
uint feeAmount = amount / Fee;
if (feeAmount == 0) throw;
balanceOf[msg.sender] += amount - feeAmount;
balanceOf[owner] += feeAmount;
totalSupply += amount;
lastBuyPrice = block.difficulty;
Buy(this, msg.sender, amount, feeAmount, block.difficulty, lastSellPrice);
}
function sell(uint256 amount) payable {
if (msg.value > 0) throw;
if (balanceOf[msg.sender] < amount) throw;
uint feeAmount = amount / Fee;
if (feeAmount == 0) throw;
balanceOf[msg.sender] -= amount;
balanceOf[owner] += feeAmount;
totalSupply = totalSupply - amount + feeAmount;
lastSellPrice = this.balance * 10**18 / totalSupply;
if (!msg.sender.send((amount - feeAmount) * lastSellPrice / 10**18)) throw;
Sell(this, msg.sender, amount, feeAmount, lastBuyPrice, lastSellPrice);
}
function () {
throw;
}
}