Contract Name:
BlockWRKICO
Contract Source Code:
File 1 of 1 : BlockWRKICO
// File: openzeppelin-solidity\contracts\token\ERC20\ERC20Basic.sol
pragma solidity 0.4.24;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* See https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: openzeppelin-solidity\contracts\token\ERC20\ERC20.sol
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address _owner, address _spender)
public view returns (uint256);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
// File: contracts\ERC865Basic.sol
/**
* @title ERC865Basic
* @dev Simpler version of the ERC865 interface from https://github.com/adilharis2001/ERC865Demo
* @author jsdavis28
* @notice ERC865Token allows for users to pay gas costs to a delegate in an ERC20 token
* https://github.com/ethereum/EIPs/issues/865
*/
contract ERC865Basic is ERC20 {
function _transferPreSigned(
bytes _signature,
address _from,
address _to,
uint256 _value,
uint256 _fee,
uint256 _nonce
)
internal;
event TransferPreSigned(
address indexed delegate,
address indexed from,
address indexed to,
uint256 value);
}
// File: openzeppelin-solidity\contracts\math\SafeMath.sol
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
// assert(_b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return _a / _b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
// File: openzeppelin-solidity\contracts\token\ERC20\BasicToken.sol
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) internal balances;
uint256 internal totalSupply_;
/**
* @dev Total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
/**
* @dev Transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
}
// File: openzeppelin-solidity\contracts\token\ERC20\StandardToken.sol
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://github.com/ethereum/EIPs/issues/20
* Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(
address _owner,
address _spender
)
public
view
returns (uint256)
{
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(
address _spender,
uint256 _addedValue
)
public
returns (bool)
{
allowed[msg.sender][_spender] = (
allowed[msg.sender][_spender].add(_addedValue));
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(
address _spender,
uint256 _subtractedValue
)
public
returns (bool)
{
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
// File: contracts\ERC865BasicToken.sol
/**
* @title ERC865BasicToken
* @dev Simpler version of the ERC865 token from https://github.com/adilharis2001/ERC865Demo
* @author jsdavis28
* @notice ERC865Token allows for users to pay gas costs to a delegate in an ERC20 token
* https://github.com/ethereum/EIPs/issues/865
*/
contract ERC865BasicToken is ERC865Basic, StandardToken {
/**
* @dev Sets internal variables for contract
*/
address internal feeAccount;
mapping(bytes => bool) internal signatures;
/**
* @dev Allows a delegate to submit a transaction on behalf of the token holder.
* @param _signature The signature, issued by the token holder.
* @param _to The recipient's address.
* @param _value The amount of tokens to be transferred.
* @param _fee The amount of tokens paid to the delegate for gas costs.
* @param _nonce The transaction number.
*/
function _transferPreSigned(
bytes _signature,
address _from,
address _to,
uint256 _value,
uint256 _fee,
uint256 _nonce
)
internal
{
//Pre-validate transaction
require(_to != address(0));
require(signatures[_signature] == false);
//Create a hash of the transaction details
bytes32 hashedTx = _transferPreSignedHashing(_to, _value, _fee, _nonce);
//Obtain the token holder's address and check balance
address from = _recover(hashedTx, _signature);
require(from == _from);
uint256 total = _value.add(_fee);
require(total <= balances[from]);
//Transfer tokens
balances[from] = balances[from].sub(_value).sub(_fee);
balances[_to] = balances[_to].add(_value);
balances[feeAccount] = balances[feeAccount].add(_fee);
//Mark transaction as completed
signatures[_signature] = true;
//TransferPreSigned ERC865 events
emit TransferPreSigned(msg.sender, from, _to, _value);
emit TransferPreSigned(msg.sender, from, feeAccount, _fee);
//Transfer ERC20 events
emit Transfer(from, _to, _value);
emit Transfer(from, feeAccount, _fee);
}
/**
* @dev Creates a hash of the transaction information passed to transferPresigned.
* @param _to address The address which you want to transfer to.
* @param _value uint256 The amount of tokens to be transferred.
* @param _fee uint256 The amount of tokens paid to msg.sender, by the owner.
* @param _nonce uint256 Presigned transaction number.
* @return A copy of the hashed message signed by the token holder, with prefix added.
*/
function _transferPreSignedHashing(
address _to,
uint256 _value,
uint256 _fee,
uint256 _nonce
)
internal pure
returns (bytes32)
{
//Create a copy of the hashed message signed by the token holder
bytes32 hash = keccak256(abi.encodePacked(_to, _value, _fee,_nonce));
//Add prefix to hash
return _prefix(hash);
}
/**
* @dev Adds prefix to the hashed message signed by the token holder.
* @param _hash The hashed message (keccak256) to be prefixed.
* @return Prefixed hashed message to return from _transferPreSignedHashing.
*/
function _prefix(bytes32 _hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash));
}
/**
* @dev Validate the transaction information and recover the token holder's address.
* @param _hash A prefixed version of the hash used in the original signed message.
* @param _sig The signature submitted by the token holder.
* @return The token holder/transaction signer's address.
*/
function _recover(bytes32 _hash, bytes _sig) internal pure returns (address) {
bytes32 r;
bytes32 s;
uint8 v;
//Check the signature length
if (_sig.length != 65) {
return (address(0));
}
//Split the signature into r, s and v variables
assembly {
r := mload(add(_sig, 32))
s := mload(add(_sig, 64))
v := byte(0, mload(add(_sig, 96)))
}
//Version of signature should be 27 or 28, but 0 and 1 are also possible
if (v < 27) {
v += 27;
}
//If the version is correct, return the signer address
if (v != 27 && v != 28) {
return (address(0));
} else {
return ecrecover(_hash, v, r, s);
}
}
}
// File: contracts\TaxedToken.sol
/**
* @title Taxed token
* @dev Version of BasicToken that allows for a fee on token transfers.
* See https://github.com/OpenZeppelin/openzeppelin-solidity/pull/788
* @author jsdavis28
*/
contract TaxedToken is ERC865BasicToken {
/**
* @dev Sets taxRate fee as public
*/
uint8 public taxRate;
/**
* @dev Transfer tokens to a specified account after diverting a fee to a central account.
* @param _to The receiving address.
* @param _value The number of tokens to transfer.
*/
function transfer(
address _to,
uint256 _value
)
public
returns (bool)
{
require(_to != address(0));
require(_value <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender].sub(_value);
uint256 fee = _value.mul(taxRate).div(100);
uint256 taxedValue = _value.sub(fee);
balances[_to] = balances[_to].add(taxedValue);
emit Transfer(msg.sender, _to, taxedValue);
balances[feeAccount] = balances[feeAccount].add(fee);
emit Transfer(msg.sender, feeAccount, fee);
return true;
}
/**
* @dev Provides a taxed transfer on StandardToken's transferFrom() function
* @param _from The address providing allowance to spend
* @param _to The receiving address.
* @param _value The number of tokens to transfer.
*/
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
uint256 fee = _value.mul(taxRate).div(100);
uint256 taxedValue = _value.sub(fee);
balances[_to] = balances[_to].add(taxedValue);
emit Transfer(_from, _to, taxedValue);
balances[feeAccount] = balances[feeAccount].add(fee);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, feeAccount, fee);
return true;
}
}
// File: openzeppelin-solidity\contracts\ownership\Ownable.sol
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
// File: contracts\Authorizable.sol
/**
* @title Authorizable
* @dev The Authorizable contract allows the owner to set a number of additional
* acccounts with limited administrative privileges to simplify user permissions.
* Only the contract owner can add or remove authorized accounts.
* @author jsdavis28
*/
contract Authorizable is Ownable {
using SafeMath for uint256;
address[] public authorized;
mapping(address => bool) internal authorizedIndex;
uint8 public numAuthorized;
/**
* @dev The Authorizable constructor sets the owner as authorized
*/
constructor() public {
authorized.length = 2;
authorized[1] = msg.sender;
authorizedIndex[msg.sender] = true;
numAuthorized = 1;
}
/**
* @dev Throws if called by any account other than an authorized account.
*/
modifier onlyAuthorized {
require(isAuthorized(msg.sender));
_;
}
/**
* @dev Allows the current owner to add an authorized account.
* @param _account The address being added as authorized.
*/
function addAuthorized(address _account) public onlyOwner {
if (authorizedIndex[_account] == false) {
authorizedIndex[_account] = true;
authorized.length++;
authorized[authorized.length.sub(1)] = _account;
numAuthorized++;
}
}
/**
* @dev Validates whether an account is authorized for enhanced permissions.
* @param _account The address being evaluated.
*/
function isAuthorized(address _account) public constant returns (bool) {
if (authorizedIndex[_account] == true) {
return true;
}
return false;
}
/**
* @dev Allows the current owner to remove an authorized account.
* @param _account The address to remove from authorized.
*/
function removeAuthorized(address _account) public onlyOwner {
require(isAuthorized(_account));
authorizedIndex[_account] = false;
numAuthorized--;
}
}
// File: contracts\BlockWRKToken.sol
/**
* @title BlockWRKToken
* @dev BlockWRKToken contains administrative features that allow the BlockWRK
* application to interface with the BlockWRK token, an ERC20-compliant token
* that integrates taxed token and ERC865 functionality.
* @author jsdavis28
*/
contract BlockWRKToken is TaxedToken, Authorizable {
/**
* @dev Sets token information.
*/
string public name = "BlockWRK";
string public symbol = "WRK";
uint8 public decimals = 4;
uint256 public INITIAL_SUPPLY;
/**
* @dev Sets public variables for BlockWRK token.
*/
address public distributionPoolWallet;
address public inAppPurchaseWallet;
address public reservedTokenWallet;
uint256 public premineDistributionPool;
uint256 public premineReserved;
/**
* @dev Sets private variables for custom token functions.
*/
uint256 internal decimalValue = 10000;
constructor() public {
feeAccount = 0xeCced56A201d1A6D1Da31A060868F96ACdba99B3;
distributionPoolWallet = 0xAB3Edd46E9D52e1b3131757e1Ed87FA885f48019;
inAppPurchaseWallet = 0x97eae8151487e054112E27D8c2eE5f17B3C6A83c;
reservedTokenWallet = 0xd6E4E287a4aE2E9d8BF7f0323f440acC0d5AD301;
premineDistributionPool = decimalValue.mul(5600000000);
premineReserved = decimalValue.mul(2000000000);
INITIAL_SUPPLY = premineDistributionPool.add(premineReserved);
balances[distributionPoolWallet] = premineDistributionPool;
emit Transfer(address(this), distributionPoolWallet, premineDistributionPool);
balances[reservedTokenWallet] = premineReserved;
emit Transfer(address(this), reservedTokenWallet, premineReserved);
totalSupply_ = INITIAL_SUPPLY;
taxRate = 2;
}
/**
* @dev Allows App to distribute WRK tokens to users.
* This function will be called by authorized from within the App.
* @param _to The recipient's BlockWRK address.
* @param _value The amount of WRK to transfer.
*/
function inAppTokenDistribution(
address _to,
uint256 _value
)
public
onlyAuthorized
{
require(_value <= balances[distributionPoolWallet]);
require(_to != address(0));
balances[distributionPoolWallet] = balances[distributionPoolWallet].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(distributionPoolWallet, _to, _value);
}
/**
* @dev Allows App to process fiat payments for WRK tokens, charging a fee in WRK.
* This function will be called by authorized from within the App.
* @param _to The buyer's BlockWRK address.
* @param _value The amount of WRK to transfer.
* @param _fee The fee charged in WRK for token purchase.
*/
function inAppTokenPurchase(
address _to,
uint256 _value,
uint256 _fee
)
public
onlyAuthorized
{
require(_value <= balances[inAppPurchaseWallet]);
require(_to != address(0));
balances[inAppPurchaseWallet] = balances[inAppPurchaseWallet].sub(_value);
uint256 netAmount = _value.sub(_fee);
balances[_to] = balances[_to].add(netAmount);
emit Transfer(inAppPurchaseWallet, _to, netAmount);
balances[feeAccount] = balances[feeAccount].add(_fee);
emit Transfer(inAppPurchaseWallet, feeAccount, _fee);
}
/**
* @dev Allows owner to set the percentage fee charged by TaxedToken on external transfers.
* @param _newRate The amount to be set.
*/
function setTaxRate(uint8 _newRate) public onlyOwner {
taxRate = _newRate;
}
/**
* @dev Allows owner to set the fee account to receive transfer fees.
* @param _newAddress The address to be set.
*/
function setFeeAccount(address _newAddress) public onlyOwner {
require(_newAddress != address(0));
feeAccount = _newAddress;
}
/**
* @dev Allows owner to set the wallet that holds WRK for sale via in-app purchases with fiat.
* @param _newAddress The address to be set.
*/
function setInAppPurchaseWallet(address _newAddress) public onlyOwner {
require(_newAddress != address(0));
inAppPurchaseWallet = _newAddress;
}
/**
* @dev Allows authorized to act as a delegate to transfer a pre-signed transaction for ERC865
* @param _signature The pre-signed message.
* @param _from The token sender.
* @param _to The token recipient.
* @param _value The amount of WRK to send the recipient.
* @param _fee The fee to be paid in WRK (calculated by App off-chain).
* @param _nonce The transaction number (stored in App off-chain).
*/
function transactionHandler(
bytes _signature,
address _from,
address _to,
uint256 _value,
uint256 _fee,
uint256 _nonce
)
public
onlyAuthorized
{
_transferPreSigned(_signature, _from, _to, _value, _fee, _nonce);
}
}
// File: contracts\BlockWRKICO.sol
/**
* @title BlockWRKICO
* @notice This contract manages the sale of WRK tokens for the BlockWRK ICO.
* @dev This contract incorporates elements of OpenZeppelin crowdsale contracts with some modifications.
* @author jsdavis28
*/
contract BlockWRKICO is BlockWRKToken {
/**
* @dev Sets public variables for BlockWRK ICO
*/
address public salesWallet;
uint256 public cap;
uint256 public closingTime;
uint256 public currentTierRate;
uint256 public openingTime;
uint256 public weiRaised;
/**
* @dev Sets private variables for custom token functions.
*/
uint256 internal availableInCurrentTier;
uint256 internal availableInSale;
uint256 internal totalPremineVolume;
uint256 internal totalSaleVolume;
uint256 internal totalTokenVolume;
uint256 internal tier1Rate;
uint256 internal tier2Rate;
uint256 internal tier3Rate;
uint256 internal tier4Rate;
uint256 internal tier5Rate;
uint256 internal tier6Rate;
uint256 internal tier7Rate;
uint256 internal tier8Rate;
uint256 internal tier9Rate;
uint256 internal tier10Rate;
uint256 internal tier1Volume;
uint256 internal tier2Volume;
uint256 internal tier3Volume;
uint256 internal tier4Volume;
uint256 internal tier5Volume;
uint256 internal tier6Volume;
uint256 internal tier7Volume;
uint256 internal tier8Volume;
uint256 internal tier9Volume;
uint256 internal tier10Volume;
constructor() public {
cap = 9999999999999999999999999999999999999999999999;
salesWallet = 0xA0E021fC3538ed52F9a3D79249ff1D3A67f91C42;
openingTime = 1557856800;
closingTime = 1589479200;
totalPremineVolume = 76000000000000;
totalSaleVolume = 43000000000000;
totalTokenVolume = 119000000000000;
availableInSale = totalSaleVolume;
tier1Rate = 100000;
tier2Rate = 10000;
tier3Rate = 2000;
tier4Rate = 1250;
tier5Rate = 625;
tier6Rate = 312;
tier7Rate = 156;
tier8Rate = 117;
tier9Rate = 104;
tier10Rate = 100;
tier1Volume = totalPremineVolume.add(1000000000000);
tier2Volume = tier1Volume.add(2000000000000);
tier3Volume = tier2Volume.add(5000000000000);
tier4Volume = tier3Volume.add(5000000000000);
tier5Volume = tier4Volume.add(5000000000000);
tier6Volume = tier5Volume.add(5000000000000);
tier7Volume = tier6Volume.add(5000000000000);
tier8Volume = tier7Volume.add(5000000000000);
tier9Volume = tier8Volume.add(5000000000000);
tier10Volume = tier9Volume.add(5000000000000);
}
/**
* Event for token purchase logging
* @param purchaser who paid for the tokens
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
event TokenPurchase(
address indexed purchaser,
address indexed beneficiary,
uint256 value,
uint256 amount
);
/**
* Event marking the transfer of any remaining WRK to the distribution pool post-ICO
* @param wallet The address remaining sale tokens are delivered
* @param amount The remaining tokens after the sale has closed
*/
event CloseoutSale(address indexed wallet, uint256 amount);
// -----------------------------------------
// Crowdsale external interface
// -----------------------------------------
/**
* @dev fallback function
*/
function () external payable {
buyTokens(msg.sender);
}
/**
* @dev Allows ICO participants to purchase WRK tokens
* @param _beneficiary The address of the ICO participant
*/
function buyTokens(address _beneficiary) public payable {
uint256 weiAmount = msg.value;
_preValidatePurchase(_beneficiary, weiAmount);
//Calculate number of tokens to issue
uint256 tokens = _calculateTokens(weiAmount);
//Calculate new amount of Wei raised
weiRaised = weiRaised.add(weiAmount);
//Process token purchase and forward funcds to salesWallet
_processPurchase(_beneficiary, tokens);
_forwardFunds();
emit TokenPurchase(msg.sender, _beneficiary, weiAmount, tokens);
}
/**
* @dev Checks whether the cap has been reached.
* @return Whether the cap was reached
*/
function capReached() public view returns (bool) {
return weiRaised >= cap;
}
/**
* @dev Checks whether the period in which the crowdsale is open has already elapsed.
* @return Whether crowdsale period has elapsed
*/
function hasClosed() public view returns (bool) {
// solium-disable-next-line security/no-block-members
return block.timestamp > closingTime;
}
// -----------------------------------------
// Internal interface (extensible)
// -----------------------------------------
/**
* @dev Calculates total number of tokens to sell, accounting for varied rates per tier.
* @param _amountWei Total amount of Wei sent by ICO participant
* @return Total number of tokens to send to buyer
*/
function _calculateTokens(uint256 _amountWei) internal returns (uint256) {
//Tokens pending in sale
uint256 tokenAmountPending;
//Tokens to be sold
uint256 tokenAmountToIssue;
//Note: tierCaps must take into account reserved and distribution pool tokens
//Determine tokens remaining in tier and set current token rate
uint256 tokensRemainingInTier = _getRemainingTokens(totalSupply_);
//Calculate new tokens pending sale
uint256 newTokens = _getTokenAmount(_amountWei);
//Check if _newTokens exceeds _tokensRemainingInTier
bool nextTier = true;
while (nextTier) {
if (newTokens > tokensRemainingInTier) {
//Get tokens sold in current tier and add to pending total supply
tokenAmountPending = tokensRemainingInTier;
uint256 newTotal = totalSupply_.add(tokenAmountPending);
//Save number of tokens pending from current tier
tokenAmountToIssue = tokenAmountToIssue.add(tokenAmountPending);
//Calculate Wei spent in current tier and set remaining Wei for next tier
uint256 pendingAmountWei = tokenAmountPending.div(currentTierRate);
uint256 remainingWei = _amountWei.sub(pendingAmountWei);
//Calculate number of tokens in next tier
tokensRemainingInTier = _getRemainingTokens(newTotal);
newTokens = _getTokenAmount(remainingWei);
} else {
tokenAmountToIssue = tokenAmountToIssue.add(newTokens);
nextTier = false;
_setAvailableInCurrentTier(tokensRemainingInTier, newTokens);
_setAvailableInSale(newTokens);
}
}
//Return amount of tokens to be issued in this sale
return tokenAmountToIssue;
}
/**
* @dev Source of tokens.
* @param _beneficiary Address performing the token purchase
* @param _tokenAmount Number of tokens to be emitted
*/
function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
totalSupply_ = totalSupply_.add(_tokenAmount);
balances[_beneficiary] = balances[_beneficiary].add(_tokenAmount);
}
/**
* @dev Determines how ETH is stored/forwarded on purchases.
*/
function _forwardFunds() internal {
salesWallet.transfer(msg.value);
}
/**
* @dev Performs a binary search of the sale tiers to determine current sales volume and rate.
* @param _tokensSold The total number of tokens sold in the ICO prior to this tx
* @return The remaining number of tokens for sale in the current sale tier
*/
function _getRemainingTokens(uint256 _tokensSold) internal returns (uint256) {
//Deteremine the current sale tier, set current rate and find remaining tokens in tier
uint256 remaining;
if (_tokensSold < tier5Volume) {
if (_tokensSold < tier3Volume) {
if (_tokensSold < tier1Volume) {
_setCurrentTierRate(tier1Rate);
remaining = tier1Volume.sub(_tokensSold);
} else if (_tokensSold < tier2Volume) {
_setCurrentTierRate(tier2Rate);
remaining = tier2Volume.sub(_tokensSold);
} else {
_setCurrentTierRate(tier3Rate);
remaining = tier3Volume.sub(_tokensSold);
}
} else {
if (_tokensSold < tier4Volume) {
_setCurrentTierRate(tier4Rate);
remaining = tier4Volume.sub(_tokensSold);
} else {
_setCurrentTierRate(tier5Rate);
remaining = tier5Volume.sub(_tokensSold);
}
}
} else {
if (_tokensSold < tier8Volume) {
if (_tokensSold < tier6Volume) {
_setCurrentTierRate(tier6Rate);
remaining = tier6Volume.sub(_tokensSold);
} else if (_tokensSold < tier7Volume) {
_setCurrentTierRate(tier7Rate);
remaining = tier7Volume.sub(_tokensSold);
} else {
_setCurrentTierRate(tier8Rate);
remaining = tier8Volume.sub(_tokensSold);
}
} else {
if (_tokensSold < tier9Volume) {
_setCurrentTierRate(tier9Rate);
remaining = tier9Volume.sub(_tokensSold);
} else {
_setCurrentTierRate(tier10Rate);
remaining = tier10Volume.sub(_tokensSold);
}
}
}
return remaining;
}
/**
* @dev Override to extend the way in which ether is converted to tokens.
* @param _weiAmount Value in wei to be converted into tokens
* @return Number of tokens that can be purchased with the specified _weiAmount
*/
function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {
return _weiAmount.mul(currentTierRate).mul(decimalValue).div(1 ether);
}
/**
* @dev Validation of an incoming purchase.
* @param _beneficiary Address performing the token purchase
* @param _weiAmount Value in wei involved in the purchase
*/
function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view {
require(_beneficiary != address(0));
require(_weiAmount != 0);
require(weiRaised.add(_weiAmount) <= cap);
// solium-disable-next-line security/no-block-members
require(block.timestamp >= openingTime && block.timestamp <= closingTime);
}
/**
* @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
* @param _beneficiary Address receiving the tokens
* @param _tokenAmount Number of tokens to be purchased
*/
function _processPurchase(address _beneficiary, uint256 _tokenAmount) internal {
_deliverTokens(_beneficiary, _tokenAmount);
}
/**
* @dev Calculates remaining tokens available in the current tier after a sale is processed
* @param _tierPreviousRemaining Number of tokens remaining prior to sale
* @param _newIssue Number of tokens to be purchased
*/
function _setAvailableInCurrentTier(uint256 _tierPreviousRemaining, uint256 _newIssue) internal {
availableInCurrentTier = _tierPreviousRemaining.sub(_newIssue);
}
/**
* @dev Calculates remaining tokens available in the ICO after a sale is processed
* @param _newIssue Number of tokens to be purchased
*/
function _setAvailableInSale(uint256 _newIssue) internal {
availableInSale = totalSaleVolume.sub(_newIssue);
}
/**
* @dev Sets the current tier rate based on sale volume
* @param _rate The new rate
*/
function _setCurrentTierRate(uint256 _rate) internal {
currentTierRate = _rate;
}
/**
* @dev Returns the remaining number of tokens for sale
* @return Total remaining tokens available for sale
*/
function tokensRemainingInSale() public view returns (uint256) {
return availableInSale;
}
/**
* @dev Returns the remaining number of tokens for sale in the current tier
* @return Total remaining tokens available for sale in the current tier
*/
function tokensRemainingInTier() public view returns (uint256) {
return availableInCurrentTier;
}
/**
* @dev Allows the owner to transfer any remaining tokens not sold to a wallet
* @return Total remaining tokens available for sale
*/
function transferRemainingTokens() public onlyOwner {
//require that sale is closed
require(hasClosed());
//require that tokens are still remaining after close
require(availableInSale > 0);
//send remaining tokens to distribution pool wallet
balances[distributionPoolWallet] = balances[distributionPoolWallet].add(availableInSale);
emit CloseoutSale(distributionPoolWallet, availableInSale);
}
}