Skip to content

Instantly share code, notes, and snippets.

@siman siman/BsTokenCrowdsale_HEW_v2.sol Secret
Last active Jul 19, 2017

Embed
What would you like to do?
Hero Engine Smart Contracts. Version 2 after fixing issues found by Ambisafe.
pragma solidity ^0.4.11;
contract SafeMath {
function safeMul(uint256 a, uint256 b) internal returns (uint256 ) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint256 a, uint256 b) internal returns (uint256 ) {
assert(b > 0);
uint256 c = a / b;
assert(a == b * c + a % b);
return c;
}
function safeSub(uint256 a, uint256 b) internal returns (uint256 ) {
assert(b <= a);
return a - b;
}
function safeAdd(uint256 a, uint256 b) internal returns (uint256 ) {
uint256 c = a + b;
assert(c >= a);
return c;
}
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
return a < b ? a : b;
}
function assert(bool assertion) internal {
if (!assertion) {
throw;
}
}
}
contract ERC20 {
/* This is a slight change to the ERC20 base standard.
function totalSupply() constant returns (uint256 supply);
is replaced with:
uint256 public totalSupply;
This automatically creates a getter function for the totalSupply.
This is moved to the base contract since public getter functions are not
currently recognised as an implementation of the matching abstract
function by the compiler.
*/
/// total amount of tokens
uint256 public totalSupply;
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) constant returns (uint256 balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _value) returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of tokens to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address _spender, uint256 _value) returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract StandardToken is ERC20, SafeMath {
mapping(address => uint256) balances;
mapping(address => mapping(address => uint256)) allowed;
/// @dev Returns number of tokens owned by given address.
/// @param _owner Address of token owner.
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
/// @dev Transfers sender's tokens to a given address. Returns success.
/// @param _to Address of token receiver.
/// @param _value Number of tokens to transfer.
function transfer(address _to, uint256 _value) returns (bool) {
if (balances[msg.sender] >= _value && _value > 0) {
balances[msg.sender] = safeSub(balances[msg.sender], _value);
balances[_to] = safeAdd(balances[_to], _value);
Transfer(msg.sender, _to, _value);
return true;
} else return false;
}
/// @dev Allows allowed third party to transfer tokens from one address to another. Returns success.
/// @param _from Address from where tokens are withdrawn.
/// @param _to Address to where tokens are sent.
/// @param _value Number of tokens to transfer.
function transferFrom(address _from, address _to, uint256 _value) returns (bool) {
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
balances[_to] = safeAdd(balances[_to], _value);
balances[_from] = safeSub(balances[_from], _value);
allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _value);
Transfer(_from, _to, _value);
return true;
} else return false;
}
/// @dev Sets approved amount of tokens for spender. Returns success.
/// @param _spender Address of allowed account.
/// @param _value Number of approved tokens.
function approve(address _spender, uint256 _value) returns (bool) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
/// @dev Returns number of allowed tokens for given address.
/// @param _owner Address of token owner.
/// @param _spender Address of token spender.
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
}
contract MultiOwnable {
mapping (address => bool) ownerMap;
address[] public owners;
event OwnerAdded(address indexed newOwner);
event OwnerRemoved(address indexed oldOwner);
modifier onlyOwner() {
if (!isOwner(msg.sender)) throw;
_;
}
function MultiOwnable() {
// Add default owner
address owner = msg.sender;
ownerMap[owner] = true;
owners.push(owner);
}
function isOwner(address owner) constant returns (bool) {
return ownerMap[owner];
}
function addOwner(address owner) onlyOwner returns (bool) {
if (!isOwner(owner) && owner != 0) {
ownerMap[owner] = true;
owners.push(owner);
OwnerAdded(owner);
return true;
} else return false;
}
function removeOwner(address owner) onlyOwner returns (bool) {
if (isOwner(owner)) {
ownerMap[owner] = false;
for (uint i = 0; i < owners.length - 1; i++) {
if (owners[i] == owner) {
owners[i] = owners[owners.length - 1];
break;
}
}
owners.length -= 1;
OwnerRemoved(owner);
return true;
} else return false;
}
}
contract Ownable {
address public owner;
address public pendingOwner;
function Ownable() {
owner = msg.sender;
}
modifier onlyOwner() {
if (msg.sender != owner) throw;
_;
}
// Safe transfer of ownership in 2 steps. Once called, a newOwner needs to call claimOwnership() to prove ownership.
function transferOwnership(address newOwner) onlyOwner {
pendingOwner = newOwner;
}
function claimOwnership() {
if (msg.sender == pendingOwner) {
owner = pendingOwner;
pendingOwner = 0;
}
}
}
contract Pausable is Ownable {
bool public stopped;
modifier stopInEmergency {
if (stopped) throw;
_;
}
modifier onlyInEmergency {
if (!stopped) throw;
_;
}
// Called by the owner on emergency, triggers stopped state
function emergencyStop() external onlyOwner {
stopped = true;
}
// Called by the owner on end of emergency, returns to normal state
function release() external onlyOwner onlyInEmergency {
stopped = false;
}
}
contract Refundable is SafeMath {
mapping(address => uint256) public payments;
uint256 public refundedWei;
event RefundWei(address to, uint256 value);
// Store sent amount as credit to be pulled, called by payer.
function pullForRefund(address dest, uint256 amount) internal {
payments[dest] = safeAdd(payments[dest], amount);
}
// Withdraw accumulated balance, called by payee.
function withdrawPayments() {
address payee = msg.sender;
uint256 payment = payments[payee];
if (payment == 0) throw;
if (this.balance < payment) throw;
payments[payee] = 0;
payee.transfer(payment);
refundedWei = safeAdd(refundedWei, payment);
RefundWei(payee, payment);
}
}
contract TokenSpender {
function receiveApproval(address _from, uint256 _value);
}
contract BsToken is StandardToken, MultiOwnable {
bool public locked;
string public name;
string public symbol;
uint256 public totalSupply;
uint8 public decimals = 18;
string public version = 'v0.1';
address public creator;
address public seller;
uint256 public tokensSold;
uint256 public totalSales;
event Sell(address indexed seller, address indexed buyer, uint256 value);
event SellerChanged(address indexed oldSeller, address indexed newSeller);
modifier onlyUnlocked() {
if (!isOwner(msg.sender) && locked) throw;
_;
}
function BsToken(string _name, string _symbol, uint256 _totalSupply, address _seller) MultiOwnable() {
// Lock the transfer function during the presale/crowdsale.
locked = true;
creator = msg.sender;
seller = _seller;
name = _name;
symbol = _symbol;
totalSupply = _totalSupply;
balances[seller] = totalSupply;
}
function changeSeller(address newSeller) onlyOwner returns (bool) {
if (newSeller == 0x0 || seller == newSeller) throw;
address oldSeller = seller;
uint256 unsoldTokens = balances[oldSeller];
balances[oldSeller] = 0;
balances[newSeller] = safeAdd(balances[newSeller], unsoldTokens);
seller = newSeller;
SellerChanged(oldSeller, newSeller);
return true;
}
function sell(address _to, uint256 _value) onlyOwner returns (bool) {
if (balances[seller] >= _value && _value > 0) {
balances[seller] = safeSub(balances[seller], _value);
balances[_to] = safeAdd(balances[_to], _value);
tokensSold = safeAdd(tokensSold, _value);
totalSales = safeAdd(totalSales, 1);
Sell(seller, _to, _value);
Transfer(seller, _to, _value);
return true;
} else return false;
}
function transfer(address _to, uint256 _value) onlyUnlocked returns (bool) {
return super.transfer(_to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) onlyUnlocked returns (bool) {
return super.transferFrom(_from, _to, _value);
}
function lock() onlyOwner {
locked = true;
}
function unlock() onlyOwner {
locked = false;
}
function burn(uint256 _value) returns (bool) {
if (balances[msg.sender] >= _value && _value > 0) {
balances[msg.sender] = safeSub(balances[msg.sender], _value) ;
totalSupply = safeSub(totalSupply, _value);
Transfer(msg.sender, 0x0, _value);
return true;
} else return false;
}
/* Approve and then communicate the approved contract in a single tx */
function approveAndCall(address _spender, uint256 _value) {
TokenSpender spender = TokenSpender(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value);
}
}
}
contract BsCrowdsale is SafeMath, Ownable, Pausable, Refundable {
struct Backer {
uint256 weiReceived; // Amount of wei given
uint256 tokensSent;
}
BsToken public token; // Token contract reference
address public multisigETH; // Multisig contract that will receive the ETH
address public bsETH; // Multisig contract of Blockstarter
uint256 public minInvestWei; // Minimum amount to invest
uint256 public tokensPerETH; // Number of tokens per ETH
uint256 public weiReceived; // Number of wei received
uint256 public tokensSentToETH; // Number of tokens sent to ETH contributors
uint256 public totalContributions;
uint256 public startTime; // Crowdsale start time in seconds (will be compared with block time)
uint256 public endTime; // Crowdsale end time in seconds (will be compared with block time)
uint256 public minCapInWei; // Minimum wei to receive
uint256 public maxCapInWei; // Maximum wei to receive
bool public saleClosed; // Is crowdsale still on going
mapping(address => Backer) public backers; // backersETH indexed by their ETH address
modifier minCapNotReached() {
if (getNow() < endTime || weiReceived >= minCapInWei) throw;
_;
}
modifier respectTimeFrame() {
if (getNow() < startTime || getNow() > endTime) throw;
_;
}
event ReceivedWei(address addr, uint256 value);
function BsCrowdsale(
address _token_address,
address _send_funds_to_address,
address _bs_address,
uint256 _min_contribution_in_wei,
uint256 _tokens_per_eth,
uint256 _ico_start_time_in_seconds,
uint256 _duration_in_days
) {
token = BsToken(_token_address);
owner = msg.sender;
multisigETH = _send_funds_to_address;
bsETH = _bs_address;
minInvestWei = _min_contribution_in_wei;
tokensPerETH = _tokens_per_eth;
tokensSentToETH = 0;
totalContributions = 0;
startTime = _ico_start_time_in_seconds;
endTime = startTime + _duration_in_days * 1 days;
minCapInWei = 3000 ether;
maxCapInWei = safeDiv(safeSub(1000000000, token.tokensSold()), _tokens_per_eth) * 1 ether;
}
// We override this method in tests to mock current time.
function getNow() constant returns (uint256) {
return now;
}
/*
* The fallback function corresponds to a donation in ETH
*/
function() payable {
sellTokens(msg.sender);
}
/*
* Receives a donation in ETH
*/
function sellTokens(address buyer) internal stopInEmergency respectTimeFrame {
if (msg.value < minInvestWei) throw; // Don't accept funding under a predefined threshold
weiReceived = safeAdd(weiReceived, msg.value); // Update the total wei collected during the crowdfunding
if (weiReceived > maxCapInWei) throw;
uint256 tokensToSend = safeDiv(safeMul(msg.value, tokensPerETH), 1 ether);
if (!token.sell(buyer, tokensToSend)) throw; // Transfer tokens to buyer.
Backer backer = backers[buyer];
backer.tokensSent = safeAdd(backer.tokensSent, tokensToSend);
backer.weiReceived = safeAdd(backer.weiReceived, msg.value); // Update the total wei collected during the crowdfunding for this backer
tokensSentToETH = safeAdd(tokensSentToETH, tokensToSend);
totalContributions = safeAdd(totalContributions, 1);
ReceivedWei(buyer, weiReceived); // send the corresponding contribution event
}
/*
* When min cap is not reach backer can call the approveAndCall function of the token contract
* with this crowdsale contract on parameter with all the tokens they get in order to be refund.
*/
function receiveApproval(address _from, uint256 _tokenCount) minCapNotReached public {
if (msg.sender != address(token)) throw; // Only token related to this crowdsale can call this method
if (_tokenCount != backers[_from].tokensSent) throw; // compare value from backer balance
if (!token.transferFrom(_from, token.seller(), _tokenCount)) throw; // get the token back to the crowdsale contract
uint256 weiToSend = backers[_from].weiReceived;
backers[_from].weiReceived = 0;
if (weiToSend > 0) {
pullForRefund(_from, weiToSend); // pull payment to get refund
}
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return token.balanceOf(_owner);
}
/*
* Finalize the crowdsale, should be called after the refund period.
*/
function finalize() onlyOwner {
// Cannot finalise before end day of crowdsale until max cap is reached.
if (weiReceived < maxCapInWei && getNow() < endTime) throw;
// If min cap is not reached contributors have 14 days to get refund before we can finalise.
if (weiReceived < minCapInWei && getNow() < endTime + 14 days) throw;
uint256 per_1 = safeDiv(this.balance, 100);
uint256 per_99 = safeSub(this.balance, per_1);
multisigETH.transfer(per_99);
// Here we using 'send' instead of 'transfer' because in a case of any problems with sending to bsETH address,
// 'transfer' will rollback 'finalize' and money will not be sent to multisigETH as well.
bsETH.send(per_1);
token.unlock();
saleClosed = true;
}
}
contract PresaleTransfer is SafeMath, Ownable, Pausable {
BsToken public token;
bool public transferred;
function PresaleTransfer(address _token_address) {
token = BsToken(_token_address);
transferred = false;
}
function transferTokens() onlyOwner returns (bool) {
if (transferred) throw;
// TODO iterate over all contributions taken from Presale.
// They will be hardcoded here one by one.
if (!token.sell(0x123, 12300)) throw;
if (!token.sell(0x456, 45600)) throw;
if (!token.sell(0x789, 78900)) throw;
// and so on...
// In a case there will be too many sell() method calls that lead to out of gas situation,
// we will create more transferTokens1,2...N methods
// to be able successfully transfer all contributions from presale.
// In the worst case we can create another similar contract to this one that will finish transfer.
transferred = true;
return true;
}
}
contract BsToken_HEW is BsToken {
function BsToken_HEW()
BsToken(
'Hero Engine World Token',
'HEW',
2000000000,
0x7Ec64cC7272eD37A71679FCF6d1568465B27A88C
) { }
}
contract BsCrowdsale_HEW is BsCrowdsale {
function BsCrowdsale_HEW()
BsCrowdsale(
0x2A2c586Cc9b0FD012b49785940Eb435cb0c26c27,
0x7Ec64cC7272eD37A71679FCF6d1568465B27A88C,
0x462D3AA87Ccaa6bB6bfA47A5b6d6A4BB39a4aBc1,
0.01 * 1 ether,
5000,
1499679669, // TODO start time will be replaced with actual once we will know exact date and time.
30
) { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.