BlockCDN (BCDN) ICO token from 1 November 2016, a decentralized CDN and bandwidth-sharing project. ERC20 token combined with a fund and refund sale mechanism.
Token Information
Key Facts
Description
BlockCDN was a decentralized content-delivery and bandwidth-sharing project. This 1 November 2016 deployment is an ERC20 token with a built-in ICO fund and refund flow (buyBlockCDN, reFund, sendRewardBlockCDN, a fund window via startTime and closeTime, and minimum and maximum funded-value caps). The on-chain code is an unpushed intermediate revision sitting between two commits of the team's Blockcdnteam/BCDNICO repo. I reconstructed it from the verified version 1.3 sibling and reached a byte-for-byte runtime match with solc v0.4.2 (optimizer ON, runs 200).
Source Verified
Byte-for-byte runtime match. solc v0.4.2+commit.af6afb04, optimizer ON, runs 200. Runtime SHA-256 a7ca7ac0d173cf1e32fc4448dcc1407978ead632c2978c97494e742518536018. Reproduce with verify.js in the proof folder.
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Tangerine Whistle Era
Emergency fork to address DoS attacks. Repriced IO-heavy opcodes.
Bytecode Overview
Verified Source Available
Source verified through compiler archaeology and exact bytecode matching.
View Verification ProofShow source code (Solidity)
pragma solidity ^0.4.2;
contract blockcdn {
mapping (address => uint256) balances;
mapping (address => uint256) fundValue;
address public owner;
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
uint256 public minFundedValue;
uint256 public maxFundedValue;
bool public isFundedMax;
bool public isFundedMini;
uint256 public closeTime;
uint256 public startTime;
/* This generates a public event on the blockchain that will notify clients */
event Transfer(address indexed from, address indexed to, uint256 value);
function blockcdn(
address _owner,
string _tokenName,
uint8 _decimalUnits,
string _tokenSymbol,
uint256 _totalSupply,
uint256 _closeTime,
uint256 _startTime,
uint256 _minValue,
uint256 _maxValue
) {
owner = _owner; // Set owner of contract
name = _tokenName; // Set the name for display purposes
symbol = _tokenSymbol; // Set the symbol for display purposes
decimals = _decimalUnits; // Amount of decimals for display purposes
closeTime = _closeTime; // Set fund closing time
startTime = _startTime; // Set fund start time
totalSupply = _totalSupply; // Total supply
minFundedValue = _minValue; // Set minimum funding goal
maxFundedValue = _maxValue; // Set max funding goal
isFundedMax = false; // Initialize fund minimum flag
isFundedMini = false; // Initialize fund max flag
balances[owner] = _totalSupply; // Set owner balance equal totalsupply
}
/*default-function called when values are sent */
function () {
buyBlockCDN();
}
/*send ethereum and get BCDN*/
function buyBlockCDN() returns (bool success){
if(msg.sender == owner) throw;
if(now > closeTime) throw;
if(now < startTime) throw;
if(isFundedMax) throw;
uint256 token = 0;
if(closeTime - 2 weeks > now) {
token = msg.value;
}else {
uint day = (now - (closeTime - 2 weeks))/(2 days) + 1;
token = msg.value;
while( day > 0) {
token = token * 95 / 100 ;
day -= 1;
}
}
balances[msg.sender] += token;
if(balances[owner] < token)
return false;
balances[owner] -= token;
if(this.balance >= minFundedValue) {
isFundedMini = true;
}
if(this.balance >= maxFundedValue) {
isFundedMax = true;
}
fundValue[msg.sender] += msg.value;
Transfer(this, msg.sender, token);
return true;
}
/*query BCDN balance*/
function balanceOf( address _owner) constant returns (uint256 value)
{
return balances[_owner];
}
/*query fund ethereum balance */
function balanceOfFund(address _owner) constant returns (uint256 value)
{
return fundValue[_owner];
}
/*refund 'msg.sender' in the case the Token Sale didn't reach ite minimum
funding goal*/
function reFund() returns (bool success) {
uint256 value = fundValue[msg.sender];
fundValue[msg.sender] = 0;
if(value <= 0) throw;
if(!msg.sender.send(value))
throw;
balances[owner] += balances[msg.sender];
balances[msg.sender] = 0;
Transfer(msg.sender, this, balances[msg.sender]);
return true;
}
/*refund _fundaddr in the case the Token Sale didn't reach ite minimum
funding goal*/
function reFundByOther(address _fundaddr) returns (bool success) {
uint256 value = fundValue[_fundaddr];
fundValue[_fundaddr] = 0;
if(value <= 0) throw;
if(!_fundaddr.send(value)) throw;
balances[owner] += balances[_fundaddr];
balances[_fundaddr] = 0;
Transfer(msg.sender, this, balances[_fundaddr]);
return true;
}
/* Send coins */
function transfer(address _to, uint256 _value) returns (bool success) {
if(_value <= 0 ) throw; // Check send token value > 0;
if (balances[msg.sender] < _value) throw; // Check if the sender has enough
if (balances[_to] + _value < balances[_to]) throw; // Check for overflows
if(now < closeTime ) { // unclosed allowed retrieval, Closed fund allow transfer
if(_to == address(this)) {
fundValue[msg.sender] -= _value;
balances[msg.sender] -= _value;
balances[owner] += _value;
if(!msg.sender.send(_value))
return false;
}
} else {
balances[msg.sender] -= _value; // Subtract from the sender
balances[_to] += _value; // Add the same to the recipient
}
Transfer(msg.sender, _to, _value); // Notify anyone listening that this transfer took place
return true;
}
/*send reward*/
function sendRewardBlockCDN(address rewarder, uint256 value) returns (bool success) {
if(msg.sender != owner) throw;
if( balances[owner] < value) throw;
balances[rewarder] += value;
uint256 halfValue = value / 2;
balances[owner] -= halfValue;
totalSupply += halfValue;
Transfer(owner, rewarder, value);
return true;
}
function modifyStartTime(uint256 _startTime) {
if(msg.sender != owner) throw;
startTime = _startTime;
}
function modifyCloseTime(uint256 _closeTime) {
if(msg.sender != owner) throw;
closeTime = _closeTime;
}
/*withDraw ethereum when closed fund*/
function withDrawEth(uint256 value) returns (bool success) {
if(now <= closeTime ) throw;
if(!isFundedMini) throw;
if(this.balance < value) throw;
if(msg.sender != owner) throw;
if(!msg.sender.send(value))
return false;
return true;
}
}