pragma solidity ^0.4.18;
/**
* Math operations with safety checks that throw on error
*/
contract SafeMath {
function safeMul(uint256 a, uint256 b) public pure returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint256 a, uint256 b) public pure returns (uint256) {
//assert(a > 0);// Solidity automatically throws when dividing by 0
//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;
}
function safeSub(uint256 a, uint256 b) public pure returns (uint256) {
assert(b <= a);
return a - b;
}
function safeAdd(uint256 a, uint256 b) public pure returns (uint256) {
uint256 c = a + b;
assert(c>=a && c>=b);
return c;
}
}
/*
* ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 {
function totalSupply() public constant returns (uint256);
function balanceOf(address _owner) public constant returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
function allowance(address _owner, address _spender) public constant returns (uint256);
/* ERC20 Events */
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract ContractReceiver {
function tokenFallback(address _from, uint256 _value, bytes _data) public;
}
contract ERC223 is ERC20 {
function transfer(address _to, uint256 _value, bytes _data) public returns (bool success);
function transfer(address _to, uint256 _value, bytes _data, string _custom_fallback) public returns (bool success);
/* ERC223 Events */
event Transfer(address indexed _from, address indexed _to, uint256 _value, bytes _data);
}
contract BankeraToken is ERC223, SafeMath {
string public constant name = "Banker Token"; // Set the name for display purposes
string public constant symbol = "BNK"; // Set the symbol for display purposes
uint8 public constant decimals = 8; // Amount of decimals for display purposes
uint256 private issued = 0; // tokens count issued to addresses
uint256 private totalTokens = 25000000000 * 100000000; //25,000,000,000.0000 0000 BNK
address private contractOwner;
address private rewardManager;
address private roundManager;
address private issueManager;
uint64 public currentRound = 0;
bool public paused = false;
mapping (uint64 => Reward) public reward; //key - round, value - reward in round
mapping (address => AddressBalanceInfoStructure) public accountBalances; //key - address, value - address balance info
mapping (uint64 => uint256) public issuedTokensInRound; //key - round, value - issued tokens
mapping (address => mapping (address => uint256)) internal allowed;
uint256 public blocksPerRound; // blocks per round
uint256 public lastBlockNumberInRound;
struct Reward {
uint64 roundNumber;
uint256 rewardInWei;
uint256 rewardRate; //reward rate in wei. 1 sBNK - xxx wei
bool isConfigured;
}
struct AddressBalanceInfoStructure {
uint256 addressBalance;
mapping (uint256 => uint256) roundBalanceMap; //key - round number, value - total token amount in round
mapping (uint64 => bool) wasModifiedInRoundMap; //key - round number, value - is modified in round
uint64[] mapKeys; //round balance map keys
uint64 claimedRewardTillRound;
uint256 totalClaimedReward;
}
/* Initializes contract with initial blocks per round number*/
function BankeraToken(uint256 _blocksPerRound, uint64 _round) public {
contractOwner = msg.sender;
lastBlockNumberInRound = block.number;
blocksPerRound = _blocksPerRound;
currentRound = _round;
}
function() public whenNotPaused payable {
}
// Public functions
/**
* @dev Reject all ERC223 compatible tokens
* @param _from address The address that is transferring the tokens
* @param _value uint256 the amount of the specified token
* @param _data Bytes The data passed from the caller.
*/
function tokenFallback(address _from, uint256 _value, bytes _data) public whenNotPaused view {
revert();
}
function setReward(uint64 _roundNumber, uint256 _roundRewardInWei) public whenNotPaused onlyRewardManager {
isNewRound();
Reward storage rewardInfo = reward[_roundNumber];
//validations
assert(rewardInfo.roundNumber == _roundNumber);
assert(!rewardInfo.isConfigured); //allow just not configured reward configuration
rewardInfo.rewardInWei = _roundRewardInWei;
if(_roundRewardInWei > 0){
rewardInfo.rewardRate = safeDiv(_roundRewardInWei, issuedTokensInRound[_roundNumber]);
}
rewardInfo.isConfigured = true;
}
/* Change contract owner */
function changeContractOwner(address _newContractOwner) public onlyContractOwner {
isNewRound();
if (_newContractOwner != contractOwner) {
contractOwner = _newContractOwner;
} else {
revert();
}
}
/* Change reward contract owner */
function changeRewardManager(address _newRewardManager) public onlyContractOwner {
isNewRound();
if (_newRewardManager != rewardManager) {
rewardManager = _newRewardManager;
} else {
revert();
}
}
/* Change round contract owner */
function changeRoundManager(address _newRoundManager) public onlyContractOwner {
isNewRound();
if (_newRoundManager != roundManager) {
roundManager = _newRoundManager;
} else {
revert();
}
}
/* Change issue contract owner */
function changeIssueManager(address _newIssueManager) public onlyContractOwner {
isNewRound();
if (_newIssueManager != issueManager) {
issueManager = _newIssueManager;
} else {
revert();
}
}
function setBlocksPerRound(uint64 _newBlocksPerRound) public whenNotPaused onlyRoundManager {
blocksPerRound = _newBlocksPerRound;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() onlyContractOwner whenNotPaused public {
paused = true;
}
/**
* @dev called by the owner to resume, returns to normal state
*/
function resume() onlyContractOwner whenPaused public {
paused = false;
}
/**
*
* permission checker
*/
modifier onlyContractOwner() {
if(msg.sender != contractOwner){
revert();
}
_;
}
/**
* set reward for round (reward admin)
*/
modifier onlyRewardManager() {
if(msg.sender != rewardManager && msg.sender != contractOwner){
revert();
}
_;
}
/**
* adjust round length (round admin)
*/
modifier onlyRoundManager() {
if(msg.sender != roundManager && msg.sender != contractOwner){
revert();
}
_;
}
/**
* issue tokens to ETH addresses (issue admin)
*/
modifier onlyIssueManager() {
if(msg.sender != issueManager && msg.sender != contractOwner){
revert();
}
_;
}
modifier notSelf(address _to) {
if(msg.sender == _to){
revert();
}
_;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*/
modifier whenNotPaused() {
require(!paused);
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*/
modifier whenPaused() {
require(paused);
_;
}
function getRoundBalance(address _address, uint256 _round) public view returns (uint256) {
return accountBalances[_address].roundBalanceMap[_round];
}
function isModifiedInRound(address _address, uint64 _round) public view returns (bool) {
return accountBalances[_address].wasModifiedInRoundMap[_round];
}
function getBalanceModificationRounds(address _address) public view returns (uint64[]) {
return accountBalances[_address].mapKeys;
}
//action for issue tokens
function issueTokens(address _receiver, uint256 _tokenAmount) public whenNotPaused onlyIssueManager {
isNewRound();
issue(_receiver, _tokenAmount);
}
function withdrawEther() public onlyContractOwner {
isNewRound();
if(this.balance > 0) {
contractOwner.transfer(this.balance);
} else {
revert();
}
}
/* Send coins from owner to other address */
/*Override*/
function transfer(address _to, uint256 _value) public notSelf(_to) whenNotPaused returns (bool success){
require(_to != address(0));
//added due to backwards compatibility reasons
bytes memory empty;
if(isContract(_to)) {
return transferToContract(msg.sender, _to, _value, empty);
}
else {
return transferToAddress(msg.sender, _to, _value, empty);
}
}
/*Override*/
function balanceOf(address _owner) public constant returns (uint256 balance) {
return accountBalances[_owner].addressBalance;
}
/*Override*/
function totalSupply() public constant returns (uint256){
return totalTokens;
}
/**
* @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
*/
/*Override*/
function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) {
require(_to != address(0));
require(_value <= allowed[_from][msg.sender]);
//added due to backwards compatibility reasons
bytes memory empty;
if(isContract(_to)) {
require(transferToContract(_from, _to, _value, empty));
}
else {
require(transferToAddress(_from, _to, _value, empty));
}
allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _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.
*/
/*Override*/
function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) {
allowed[msg.sender][_spender] = _value;
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.
*/
/*Override*/
function allowance(address _owner, address _spender) public view whenNotPaused 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] = safeAdd(allowed[msg.sender][_spender], _addedValue);
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] = safeSub(oldValue, _subtractedValue);
}
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
// Function that is called when a user or another contract wants to transfer funds .
/*Override*/
function transfer(address _to, uint256 _value, bytes _data) public whenNotPaused notSelf(_to) returns (bool success){
require(_to != address(0));
if(isContract(_to)) {
return transferToContract(msg.sender, _to, _value, _data);
}
else {
return transferToAddress(msg.sender, _to, _value, _data);
}
}
// Function that is called when a user or another contract wants to transfer funds.
/*Override*/
function transfer(address _to, uint256 _value, bytes _data, string _custom_fallback) public whenNotPaused notSelf(_to) returns (bool success){
require(_to != address(0));
if(isContract(_to)) {
if(accountBalances[msg.sender].addressBalance < _value){ // Check if the sender has enough
revert();
}
if(safeAdd(accountBalances[_to].addressBalance, _value) < accountBalances[_to].addressBalance){ // Check for overflows
revert();
}
isNewRound();
subFromAddressBalancesInfo(msg.sender, _value); // Subtract from the sender
addToAddressBalancesInfo(_to, _value); // Add the same to the recipient
assert(_to.call.value(0)(bytes4(keccak256(_custom_fallback)), msg.sender, _value, _data));
/* Notify anyone listening that this transfer took place */
Transfer(msg.sender, _to, _value, _data);
Transfer(msg.sender, _to, _value);
return true;
}
else {
return transferToAddress(msg.sender, _to, _value, _data);
}
}
function claimReward() public whenNotPaused returns (uint256 rewardAmountInWei) {
isNewRound();
return claimRewardTillRound(currentRound);
}
function claimRewardTillRound(uint64 _claimTillRound) public whenNotPaused returns (uint256 rewardAmountInWei) {
isNewRound();
rewardAmountInWei = calculateClaimableRewardTillRound(msg.sender, _claimTillRound);
accountBalances[msg.sender].claimedRewardTillRound = _claimTillRound;
if (rewardAmountInWei > 0){
accountBalances[msg.sender].totalClaimedReward = safeAdd(accountBalances[msg.sender].totalClaimedReward, rewardAmountInWei);
msg.sender.transfer(rewardAmountInWei);
}
return rewardAmountInWei;
}
function calculateClaimableReward(address _address) public constant returns (uint256 rewardAmountInWei) {
return calculateClaimableRewardTillRound(_address, currentRound);
}
function calculateClaimableRewardTillRound(address _address, uint64 _claimTillRound) public constant returns (uint256) {
uint256 rewardAmountInWei = 0;
if (_claimTillRound > currentRound) { revert(); }
if (currentRound < 1) { revert(); }
AddressBalanceInfoStructure storage accountBalanceInfo = accountBalances[_address];
if(accountBalanceInfo.mapKeys.length == 0){ revert(); }
uint64 userLastClaimedRewardRound = accountBalanceInfo.claimedRewardTillRound;
if (_claimTillRound < userLastClaimedRewardRound) { revert(); }
for (uint64 workRound = userLastClaimedRewardRound; workRound < _claimTillRound; workRound++) {
Reward storage rewardInfo = reward[workRound];
assert(rewardInfo.isConfigured); //don't allow to withdraw reward if affected reward is not configured
if(accountBalanceInfo.wasModifiedInRoundMap[workRound]){
rewardAmountInWei = safeAdd(rewardAmountInWei, safeMul(accountBalanceInfo.roundBalanceMap[workRound], rewardInfo.rewardRate));
} else {
uint64 lastBalanceModifiedRound = 0;
for (uint256 i = accountBalanceInfo.mapKeys.length; i > 0; i--) {
uint64 modificationInRound = accountBalanceInfo.mapKeys[i-1];
if (modificationInRound <= workRound) {
lastBalanceModifiedRound = modificationInRound;
break;
}
}
rewardAmountInWei = safeAdd(rewardAmountInWei, safeMul(accountBalanceInfo.roundBalanceMap[lastBalanceModifiedRound], rewardInfo.rewardRate));
}
}
return rewardAmountInWei;
}
function createRounds(uint256 maxRounds) public {
uint256 blocksAfterLastRound = safeSub(block.number, lastBlockNumberInRound); //current block number - last round block number = blocks after last round
if(blocksAfterLastRound >= blocksPerRound){ // need to increase reward round if blocks after last round is greater or equal blocks per round
uint256 roundsNeedToCreate = safeDiv(blocksAfterLastRound, blocksPerRound); //calculate how many rounds need to create
if(roundsNeedToCreate > maxRounds){
roundsNeedToCreate = maxRounds;
}
lastBlockNumberInRound = safeAdd(lastBlockNumberInRound, safeMul(roundsNeedToCreate, blocksPerRound));
for (uint256 i = 0; i < roundsNeedToCreate; i++) {
updateRoundInformation();
}
}
}
// Private functions
//assemble the given address bytecode. If bytecode exists then the _address is a contract.
function isContract(address _address) private view returns (bool is_contract) {
uint256 length;
assembly {
//retrieve the size of the code on target address, this needs assembly
length := extcodesize(_address)
}
return (length > 0);
}
function isNewRound() private {
uint256 blocksAfterLastRound = safeSub(block.number, lastBlockNumberInRound); //current block number - last round block number = blocks after last round
if(blocksAfterLastRound >= blocksPerRound){ // need to increase reward round if blocks after last round is greater or equal blocks per round
updateRoundsInformation(blocksAfterLastRound);
}
}
function updateRoundsInformation(uint256 _blocksAfterLastRound) private {
uint256 roundsNeedToCreate = safeDiv(_blocksAfterLastRound, blocksPerRound); //calculate how many rounds need to create
lastBlockNumberInRound = safeAdd(lastBlockNumberInRound, safeMul(roundsNeedToCreate, blocksPerRound)); //calculate last round creation block number
for (uint256 i = 0; i < roundsNeedToCreate; i++) {
updateRoundInformation();
}
}
function updateRoundInformation() private {
issuedTokensInRound[currentRound] = issued;
Reward storage rewardInfo = reward[currentRound];
rewardInfo.roundNumber = currentRound;
currentRound = currentRound + 1;
}
function issue(address _receiver, uint256 _tokenAmount) private {
if(_tokenAmount == 0){
revert();
}
uint256 newIssuedAmount = safeAdd(_tokenAmount, issued);
if(newIssuedAmount > totalTokens){
revert();
}
addToAddressBalancesInfo(_receiver, _tokenAmount);
issued = newIssuedAmount;
bytes memory empty;
if(isContract(_receiver)) {
ContractReceiver receiverContract = ContractReceiver(_receiver);
receiverContract.tokenFallback(msg.sender, _tokenAmount, empty);
}
/* Notify anyone listening that this transfer took place */
Transfer(msg.sender, _receiver, _tokenAmount, empty);
Transfer(msg.sender, _receiver, _tokenAmount);
}
function addToAddressBalancesInfo(address _receiver, uint256 _tokenAmount) private {
AddressBalanceInfoStructure storage accountBalance = accountBalances[_receiver];
if(!accountBalance.wasModifiedInRoundMap[currentRound]){ //allow just push one time per round
// If user first time get update balance set user claimed reward round to round before.
if(accountBalance.mapKeys.length == 0 && currentRound > 0){
accountBalance.claimedRewardTillRound = currentRound;
}
accountBalance.mapKeys.push(currentRound);
accountBalance.wasModifiedInRoundMap[currentRound] = true;
}
accountBalance.addressBalance = safeAdd(accountBalance.addressBalance, _tokenAmount);
accountBalance.roundBalanceMap[currentRound] = accountBalance.addressBalance;
}
function subFromAddressBalancesInfo(address _adr, uint256 _tokenAmount) private {
AddressBalanceInfoStructure storage accountBalance = accountBalances[_adr];
if(!accountBalance.wasModifiedInRoundMap[currentRound]){ //allow just push one time per round
accountBalance.mapKeys.push(currentRound);
accountBalance.wasModifiedInRoundMap[currentRound] = true;
}
accountBalance.addressBalance = safeSub(accountBalance.addressBalance, _tokenAmount);
accountBalance.roundBalanceMap[currentRound] = accountBalance.addressBalance;
}
//function that is called when transaction target is an address
function transferToAddress(address _from, address _to, uint256 _value, bytes _data) private returns (bool success) {
if(accountBalances[_from].addressBalance < _value){ // Check if the sender has enough
revert();
}
if(safeAdd(accountBalances[_to].addressBalance, _value) < accountBalances[_to].addressBalance){ // Check for overflows
revert();
}
isNewRound();
subFromAddressBalancesInfo(_from, _value); // Subtract from the sender
addToAddressBalancesInfo(_to, _value); // Add the same to the recipient
/* Notify anyone listening that this transfer took place */
Transfer(_from, _to, _value, _data);
Transfer(_from, _to, _value);
return true;
}
//function that is called when transaction target is a contract
function transferToContract(address _from, address _to, uint256 _value, bytes _data) private returns (bool success) {
if(accountBalances[_from].addressBalance < _value){ // Check if the sender has enough
revert();
}
if(safeAdd(accountBalances[_to].addressBalance, _value) < accountBalances[_to].addressBalance){ // Check for overflows
revert();
}
isNewRound();
subFromAddressBalancesInfo(_from, _value); // Subtract from the sender
addToAddressBalancesInfo(_to, _value); // Add the same to the recipient
ContractReceiver receiver = ContractReceiver(_to);
receiver.tokenFallback(_from, _value, _data);
/* Notify anyone listening that this transfer took place */
Transfer(_from, _to, _value, _data);
Transfer(_from, _to, _value);
return true;
}
}
{
"compilationTarget": {
"BankeraToken.sol": "BankeraToken"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint64"}],"name":"reward","outputs":[{"name":"roundNumber","type":"uint64"},{"name":"rewardInWei","type":"uint256"},{"name":"rewardRate","type":"uint256"},{"name":"isConfigured","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_roundNumber","type":"uint64"},{"name":"_roundRewardInWei","type":"uint256"}],"name":"setReward","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"},{"name":"_round","type":"uint64"}],"name":"isModifiedInRound","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"},{"name":"_claimTillRound","type":"uint64"}],"name":"calculateClaimableRewardTillRound","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newBlocksPerRound","type":"uint64"}],"name":"setBlocksPerRound","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newContractOwner","type":"address"}],"name":"changeContractOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_receiver","type":"address"},{"name":"_tokenAmount","type":"uint256"}],"name":"issueTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newIssueManager","type":"address"}],"name":"changeIssueManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"blocksPerRound","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"accountBalances","outputs":[{"name":"addressBalance","type":"uint256"},{"name":"claimedRewardTillRound","type":"uint64"},{"name":"totalClaimedReward","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdrawEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"maxRounds","type":"uint256"}],"name":"createRounds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_claimTillRound","type":"uint64"}],"name":"claimRewardTillRound","outputs":[{"name":"rewardAmountInWei","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentRound","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"},{"name":"_round","type":"uint256"}],"name":"getRoundBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"calculateClaimableReward","outputs":[{"name":"rewardAmountInWei","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"safeSub","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"safeDiv","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"claimReward","outputs":[{"name":"rewardAmountInWei","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_from","type":"address"},{"name":"_value","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newRoundManager","type":"address"}],"name":"changeRoundManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"getBalanceModificationRounds","outputs":[{"name":"","type":"uint64[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"safeMul","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_newRewardManager","type":"address"}],"name":"changeRewardManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"safeAdd","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_data","type":"bytes"},{"name":"_custom_fallback","type":"string"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"lastBlockNumberInRound","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint64"}],"name":"issuedTokensInRound","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_blocksPerRound","type":"uint256"},{"name":"_round","type":"uint64"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"},{"indexed":false,"name":"_data","type":"bytes"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]