/*
* Submitted for verification at etherscan.io on 2020-06-10
*
* ________ ____ _ __ __ ______________
* /_ __/ /_ ___ / __ \___ _ _____ __________(_) /_ / /__ / _/ ____/ __ \
* / / / __ \/ _ \ / /_/ / _ \ | / / _ \/ ___/ ___/ / __ \/ / _ \ / // / / / / /
* / / / / / / __/ / _, _/ __/ |/ / __/ / (__ ) / /_/ / / __/ _/ // /___/ /_/ /
* /_/ /_/ /_/\___/ /_/ |_|\___/|___/\___/_/ /____/_/_.___/_/\___/ /___/\____/\____/
*
*
* source https://github.com/lukso-network/rICO-smart-contracts
* @name Reversible ICO
* @author Fabian Vogelsteller <@frozeman>, Micky Socaci <micky@binarzone.com>, Marjorie Hernandez <marjorie@lukso.io>
* @license Apache 2.0
*
* Readme more about it here https://medium.com/lukso/rico-the-reversible-ico-5392bf64318b
*/
pragma solidity ^0.5.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}
interface IERC777 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function granularity() external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function send(address recipient, uint256 amount, bytes calldata data) external;
function burn(uint256 amount, bytes calldata data) external;
function isOperatorFor(address operator, address tokenHolder) external view returns (bool);
function authorizeOperator(address operator) external;
function revokeOperator(address operator) external;
function defaultOperators() external view returns (address[] memory);
function operatorSend(
address sender,
address recipient,
uint256 amount,
bytes calldata data,
bytes calldata operatorData
) external;
function operatorBurn(
address account,
uint256 amount,
bytes calldata data,
bytes calldata operatorData
) external;
event Sent(
address indexed operator,
address indexed from,
address indexed to,
uint256 amount,
bytes data,
bytes operatorData
);
event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);
event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);
event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
event RevokedOperator(address indexed operator, address indexed tokenHolder);
}
interface IERC777Recipient {
function tokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes calldata userData,
bytes calldata operatorData
) external;
}
interface IERC1820Registry {
function setManager(address account, address newManager) external;
function getManager(address account) external view returns (address);
function setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external;
function getInterfaceImplementer(address account, bytes32 interfaceHash) external view returns (address);
function interfaceHash(string calldata interfaceName) external pure returns (bytes32);
function updateERC165Cache(address account, bytes4 interfaceId) external;
function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);
function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);
event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);
event ManagerChanged(address indexed account, address indexed newManager);
}
contract ReversibleICO is IERC777Recipient {
using SafeMath for uint256;
IERC1820Registry private ERC1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");
bool public initialized;
bool public frozen;
uint256 public frozenPeriod;
uint256 public freezeStart;
address public deployingAddress;
address public tokenAddress;
address public projectAddress;
address public whitelistingAddress;
address public freezerAddress;
address public rescuerAddress;
uint256 public initialTokenSupply;
uint256 public tokenSupply;
uint256 public committedETH;
uint256 public pendingETH;
uint256 public canceledETH;
uint256 public withdrawnETH;
uint256 public projectWithdrawCount;
uint256 public projectWithdrawnETH;
uint256 public minContribution = 0.1 ether;
uint256 public maxContribution = 4000 ether;
mapping(uint8 => Stage) public stages;
uint8 public stageCount;
mapping(address => Participant) public participants;
mapping(uint256 => address) public participantsById;
uint256 public participantCount;
uint256 public commitPhasePrice;
uint256 public commitPhaseStartBlock;
uint256 public commitPhaseEndBlock;
uint256 public commitPhaseBlockCount;
uint256 public buyPhaseStartBlock;
uint256 public buyPhaseEndBlock;
uint256 public buyPhaseBlockCount;
uint256 internal _projectCurrentlyReservedETH;
uint256 internal _projectUnlockedETH;
uint256 internal _projectLastBlock;
struct Stage {
uint256 tokenLimit;
uint256 tokenPrice;
}
struct Participant {
bool whitelisted;
uint32 contributions;
uint32 withdraws;
uint256 firstContributionBlock;
uint256 reservedTokens;
uint256 committedETH;
uint256 pendingETH;
uint256 _currentReservedTokens;
uint256 _unlockedTokens;
uint256 _lastBlock;
mapping(uint8 => ParticipantStageDetails) stages;
}
struct ParticipantStageDetails {
uint256 pendingETH;
}
event PendingContributionAdded(address indexed participantAddress, uint256 indexed amount, uint32 indexed contributionId, uint8 stageId);
event PendingContributionsCanceled(address indexed participantAddress, uint256 indexed amount, uint32 indexed contributionId);
event WhitelistApproved(address indexed participantAddress, uint256 indexed pendingETH, uint32 indexed contributions);
event WhitelistRejected(address indexed participantAddress, uint256 indexed pendingETH, uint32 indexed contributions);
event ContributionsAccepted(address indexed participantAddress, uint256 indexed ethAmount, uint256 indexed tokenAmount, uint8 stageId);
event ProjectWithdraw(address indexed projectAddress, uint256 indexed amount, uint32 indexed withdrawCount);
event ParticipantWithdraw(address indexed participantAddress, uint256 indexed ethAmount, uint256 indexed tokenAmount, uint32 withdrawCount);
event StageChanged(uint8 indexed stageId, uint256 indexed tokenLimit, uint256 indexed tokenPrice, uint256 effectiveBlockNumber);
event WhitelistingAddressChanged(address indexed whitelistingAddress, uint8 indexed stageId, uint256 indexed effectiveBlockNumber);
event FreezerAddressChanged(address indexed freezerAddress, uint8 indexed stageId, uint256 indexed effectiveBlockNumber);
event SecurityFreeze(address indexed freezerAddress, uint8 indexed stageId, uint256 indexed effectiveBlockNumber);
event SecurityUnfreeze(address indexed freezerAddress, uint8 indexed stageId, uint256 indexed effectiveBlockNumber);
event SecurityDisableEscapeHatch(address indexed freezerAddress, uint8 indexed stageId, uint256 indexed effectiveBlockNumber);
event SecurityEscapeHatch(address indexed rescuerAddress, address indexed to, uint8 indexed stageId, uint256 effectiveBlockNumber);
event TransferEvent (
uint8 indexed typeId,
address indexed relatedAddress,
uint256 indexed value
);
enum TransferTypes {
NOT_SET,
WHITELIST_REJECTED,
CONTRIBUTION_CANCELED,
CONTRIBUTION_ACCEPTED_OVERFLOW,
PARTICIPANT_WITHDRAW,
PARTICIPANT_WITHDRAW_OVERFLOW,
PROJECT_WITHDRAWN,
FROZEN_ESCAPEHATCH_TOKEN,
FROZEN_ESCAPEHATCH_ETH
}
constructor() public {
deployingAddress = msg.sender;
ERC1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, address(this));
}
function init(
address _tokenAddress,
address _whitelistingAddress,
address _freezerAddress,
address _rescuerAddress,
address _projectAddress,
uint256 _commitPhaseStartBlock,
uint256 _buyPhaseStartBlock,
uint256 _buyPhaseEndBlock,
uint256 _initialPrice,
uint8 _stageCount,
uint256 _stageTokenLimitIncrease,
uint256 _stagePriceIncrease
)
public
onlyDeployingAddress
isNotInitialized
{
require(_tokenAddress != address(0), "_tokenAddress cannot be 0x");
require(_whitelistingAddress != address(0), "_whitelistingAddress cannot be 0x");
require(_freezerAddress != address(0), "_freezerAddress cannot be 0x");
require(_rescuerAddress != address(0), "_rescuerAddress cannot be 0x");
require(_projectAddress != address(0), "_projectAddress cannot be 0x");
tokenAddress = _tokenAddress;
whitelistingAddress = _whitelistingAddress;
freezerAddress = _freezerAddress;
rescuerAddress = _rescuerAddress;
projectAddress = _projectAddress;
commitPhaseStartBlock = _commitPhaseStartBlock;
commitPhaseEndBlock = _buyPhaseStartBlock.sub(1);
commitPhaseBlockCount = commitPhaseEndBlock.sub(commitPhaseStartBlock).add(1);
commitPhasePrice = _initialPrice;
stageCount = _stageCount;
Stage storage commitPhase = stages[0];
commitPhase.tokenLimit = _stageTokenLimitIncrease;
commitPhase.tokenPrice = _initialPrice;
uint256 previousStageTokenLimit = _stageTokenLimitIncrease;
for (uint8 i = 1; i <= _stageCount; i++) {
Stage storage byStage = stages[i];
byStage.tokenLimit = previousStageTokenLimit.add(_stageTokenLimitIncrease);
previousStageTokenLimit = byStage.tokenLimit;
byStage.tokenPrice = _initialPrice.add(_stagePriceIncrease.mul(i));
}
buyPhaseStartBlock = _buyPhaseStartBlock;
buyPhaseEndBlock = _buyPhaseEndBlock;
buyPhaseBlockCount = buyPhaseEndBlock.sub(buyPhaseStartBlock).add(1);
initialized = true;
}
function()
external
payable
isInitialized
isNotFrozen
{
Participant storage participantStats = participants[msg.sender];
if (participantStats.whitelisted == true && participantStats.contributions > 0) {
commit();
} else {
require(msg.value < minContribution, 'To contribute call commit() [0x3c7a3aff] and send ETH along.');
cancelPendingContributions(msg.sender, msg.value);
}
}
function tokensReceived(
address,
address _from,
address,
uint256 _amount,
bytes calldata,
bytes calldata
)
external
isInitialized
isNotFrozen
{
require(msg.sender == tokenAddress, "Unknown token contract sent tokens.");
if (_from == projectAddress) {
tokenSupply = tokenSupply.add(_amount);
initialTokenSupply = initialTokenSupply.add(_amount);
} else {
withdraw(_from, _amount);
}
}
function commit()
public
payable
isInitialized
isNotFrozen
isRunning
{
require(msg.value >= minContribution, "Value sent is less than the minimum contribution.");
uint8 currentStage = getCurrentStage();
Participant storage participantStats = participants[msg.sender];
ParticipantStageDetails storage byStage = participantStats.stages[currentStage];
require(participantStats.committedETH.add(msg.value) <= maxContribution, "Value sent is larger than the maximum contribution.");
if (participantStats.contributions == 0) {
participantsById[participantCount] = msg.sender;
participantCount++;
}
participantStats.contributions++;
participantStats.pendingETH = participantStats.pendingETH.add(msg.value);
byStage.pendingETH = byStage.pendingETH.add(msg.value);
pendingETH = pendingETH.add(msg.value);
emit PendingContributionAdded(
msg.sender,
msg.value,
uint32(participantStats.contributions),
currentStage
);
if (participantStats.whitelisted == true) {
acceptContributions(msg.sender);
}
}
function cancel()
external
payable
isInitialized
isNotFrozen
{
cancelPendingContributions(msg.sender, msg.value);
}
function whitelist(address[] calldata _addresses, bool _approve)
external
onlyWhitelistingAddress
isInitialized
isNotFrozen
isRunning
{
require(_addresses.length > 0, "No addresses given to whitelist.");
for (uint256 i = 0; i < _addresses.length; i++) {
address participantAddress = _addresses[i];
Participant storage participantStats = participants[participantAddress];
if (_approve) {
if (participantStats.whitelisted == false) {
participantStats.whitelisted = true;
emit WhitelistApproved(participantAddress, participantStats.pendingETH, uint32(participantStats.contributions));
}
acceptContributions(participantAddress);
} else {
participantStats.whitelisted = false;
emit WhitelistRejected(participantAddress, participantStats.pendingETH, uint32(participantStats.contributions));
cancelPendingContributions(participantAddress, 0);
}
}
}
function projectTokenWithdraw(uint256 _tokenAmount)
external
onlyProjectAddress
isInitialized
{
require(_tokenAmount <= tokenSupply, "Requested amount too high, not enough tokens available.");
tokenSupply = tokenSupply.sub(_tokenAmount);
initialTokenSupply = initialTokenSupply.sub(_tokenAmount);
IERC777(tokenAddress).send(projectAddress, _tokenAmount, "");
}
function projectWithdraw(uint256 _ethAmount)
external
onlyProjectAddress
isInitialized
isNotFrozen
{
calcProjectAllocation();
uint256 availableForWithdraw = _projectUnlockedETH.sub(projectWithdrawnETH);
require(_ethAmount <= availableForWithdraw, "Requested amount too high, not enough ETH unlocked.");
projectWithdrawCount++;
projectWithdrawnETH = projectWithdrawnETH.add(_ethAmount);
emit ProjectWithdraw(
projectAddress,
_ethAmount,
uint32(projectWithdrawCount)
);
emit TransferEvent(
uint8(TransferTypes.PROJECT_WITHDRAWN),
projectAddress,
_ethAmount
);
address(uint160(projectAddress)).transfer(_ethAmount);
}
function changeStage(uint8 _stageId, uint256 _tokenLimit, uint256 _tokenPrice)
external
onlyProjectAddress
isInitialized
{
stages[_stageId].tokenLimit = _tokenLimit;
stages[_stageId].tokenPrice = _tokenPrice;
if(_stageId > stageCount) {
stageCount = _stageId;
}
emit StageChanged(_stageId, _tokenLimit, _tokenPrice, getCurrentEffectiveBlockNumber());
}
function changeWhitelistingAddress(address _newAddress)
external
onlyProjectAddress
isInitialized
{
whitelistingAddress = _newAddress;
emit WhitelistingAddressChanged(whitelistingAddress, getCurrentStage(), getCurrentEffectiveBlockNumber());
}
function changeFreezerAddress(address _newAddress)
external
onlyProjectAddress
isInitialized
{
freezerAddress = _newAddress;
emit FreezerAddressChanged(freezerAddress, getCurrentStage(), getCurrentEffectiveBlockNumber());
}
function freeze()
external
onlyFreezerAddress
isNotFrozen
{
frozen = true;
freezeStart = getCurrentEffectiveBlockNumber();
emit SecurityFreeze(freezerAddress, getCurrentStage(), freezeStart);
}
function unfreeze()
external
onlyFreezerAddress
isFrozen
{
uint256 currentBlock = getCurrentEffectiveBlockNumber();
frozen = false;
frozenPeriod = frozenPeriod.add(
currentBlock.sub(freezeStart)
);
emit SecurityUnfreeze(freezerAddress, getCurrentStage(), currentBlock);
}
function disableEscapeHatch()
external
onlyFreezerAddress
isNotFrozen
{
freezerAddress = address(0);
rescuerAddress = address(0);
emit SecurityDisableEscapeHatch(freezerAddress, getCurrentStage(), getCurrentEffectiveBlockNumber());
}
function escapeHatch(address _to)
external
onlyRescuerAddress
isFrozen
{
require(getCurrentEffectiveBlockNumber() == freezeStart.add(18000), 'Let it cool.. Wait at least ~3 days (18000 blk) before moving anything.');
uint256 tokenBalance = IERC777(tokenAddress).balanceOf(address(this));
uint256 ethBalance = address(this).balance;
IERC777(tokenAddress).send(_to, tokenBalance, "");
address(uint160(_to)).transfer(ethBalance);
emit SecurityEscapeHatch(rescuerAddress, _to, getCurrentStage(), getCurrentEffectiveBlockNumber());
emit TransferEvent(uint8(TransferTypes.FROZEN_ESCAPEHATCH_TOKEN), _to, tokenBalance);
emit TransferEvent(uint8(TransferTypes.FROZEN_ESCAPEHATCH_ETH), _to, ethBalance);
}
function getUnlockedProjectETH() public view returns (uint256) {
uint256 newlyUnlockedEth = calcUnlockedAmount(_projectCurrentlyReservedETH, _projectLastBlock);
return _projectUnlockedETH
.add(newlyUnlockedEth);
}
function getAvailableProjectETH() public view returns (uint256) {
return getUnlockedProjectETH()
.sub(projectWithdrawnETH);
}
function getParticipantReservedTokens(address _participantAddress) public view returns (uint256) {
Participant storage participantStats = participants[_participantAddress];
if(participantStats._currentReservedTokens == 0) {
return 0;
}
return participantStats._currentReservedTokens.sub(
calcUnlockedAmount(participantStats._currentReservedTokens, participantStats._lastBlock)
);
}
function getParticipantUnlockedTokens(address _participantAddress) public view returns (uint256) {
Participant storage participantStats = participants[_participantAddress];
return participantStats._unlockedTokens.add(
calcUnlockedAmount(participantStats._currentReservedTokens, participantStats._lastBlock)
);
}
function getAvailableTokenAtCurrentStage() public view returns (uint256) {
return stages[getCurrentStage()].tokenLimit.sub(
initialTokenSupply.sub(tokenSupply)
);
}
function getCurrentStage() public view returns (uint8) {
return getStageByTokenLimit(
initialTokenSupply.sub(tokenSupply)
);
}
function getCurrentPrice() public view returns (uint256) {
return getPriceAtStage(getCurrentStage());
}
function getPriceAtStage(uint8 _stageId) public view returns (uint256) {
if (_stageId <= stageCount) {
return stages[_stageId].tokenPrice;
}
return stages[stageCount].tokenPrice;
}
function getPriceForTokenLimit(uint256 _tokenLimit) public view returns (uint256) {
return getPriceAtStage(getStageByTokenLimit(_tokenLimit));
}
function getStageByTokenLimit(uint256 _tokenLimit) public view returns (uint8) {
for (uint8 stageId = 0; stageId <= stageCount; stageId++) {
if(_tokenLimit <= stages[stageId].tokenLimit) {
return stageId;
}
}
return stageCount;
}
function committableEthAtStage(uint8 _stageId, uint8 _currentStage) public view returns (uint256) {
uint256 supply;
if(_stageId < _currentStage) {
return 0;
} else if(_stageId >= stageCount) {
supply = tokenSupply;
} else if(_stageId == _currentStage) {
supply = stages[_currentStage].tokenLimit.sub(
initialTokenSupply.sub(tokenSupply)
);
} else if(_stageId > _currentStage) {
supply = stages[_stageId].tokenLimit.sub(stages[_stageId - 1].tokenLimit);
}
return getEthAmountForTokensAtStage(
supply
, _stageId);
}
function getEthAmountForTokensAtStage(uint256 _tokenAmount, uint8 _stageId) public view returns (uint256) {
return _tokenAmount
.mul(stages[_stageId].tokenPrice)
.div(10 ** 18);
}
function getTokenAmountForEthAtStage(uint256 _ethAmount, uint8 _stageId) public view returns (uint256) {
return _ethAmount
.mul(10 ** 18)
.div(stages[_stageId].tokenPrice);
}
function getCurrentBlockNumber() public view returns (uint256) {
return uint256(block.number);
}
function getCurrentEffectiveBlockNumber() public view returns (uint256) {
return uint256(block.number)
.sub(frozenPeriod);
}
function calcUnlockedAmount(uint256 _amount, uint256 _lastBlock) public view returns (uint256) {
uint256 currentBlock = getCurrentEffectiveBlockNumber();
if(_amount == 0) {
return 0;
}
if (currentBlock >= buyPhaseStartBlock && currentBlock < buyPhaseEndBlock) {
uint256 lastBlock = _lastBlock;
if(lastBlock < buyPhaseStartBlock) {
lastBlock = buyPhaseStartBlock.sub(1);
}
uint256 passedBlocks = currentBlock.sub(lastBlock);
uint256 totalBlockCount = buyPhaseEndBlock.sub(lastBlock);
return _amount.mul(
passedBlocks.mul(10 ** 20)
.div(totalBlockCount)
).div(10 ** 20);
} else if (currentBlock >= buyPhaseEndBlock) {
return _amount;
}
return 0;
}
function sanityCheckProject() internal view {
require(
committedETH == _projectCurrentlyReservedETH.add(_projectUnlockedETH),
'Project Sanity check failed! Reserved + Unlock must equal committedETH'
);
require(
address(this).balance == _projectUnlockedETH.add(_projectCurrentlyReservedETH).add(pendingETH).sub(projectWithdrawnETH),
'Project sanity check failed! balance = Unlock + Reserved - Withdrawn'
);
}
function sanityCheckParticipant(address _participantAddress) internal view {
Participant storage participantStats = participants[_participantAddress];
require(
participantStats.reservedTokens == participantStats._currentReservedTokens.add(participantStats._unlockedTokens),
'Participant Sanity check failed! Reser. + Unlock must equal totalReser'
);
}
function calcProjectAllocation() internal {
uint256 newlyUnlockedEth = calcUnlockedAmount(_projectCurrentlyReservedETH, _projectLastBlock);
_projectCurrentlyReservedETH = _projectCurrentlyReservedETH.sub(newlyUnlockedEth);
_projectUnlockedETH = _projectUnlockedETH.add(newlyUnlockedEth);
_projectLastBlock = getCurrentEffectiveBlockNumber();
sanityCheckProject();
}
function calcParticipantAllocation(address _participantAddress) internal {
Participant storage participantStats = participants[_participantAddress];
participantStats._unlockedTokens = getParticipantUnlockedTokens(_participantAddress);
participantStats._currentReservedTokens = getParticipantReservedTokens(_participantAddress);
participantStats._lastBlock = getCurrentEffectiveBlockNumber();
calcProjectAllocation();
}
function cancelPendingContributions(address _participantAddress, uint256 _sentValue)
internal
isInitialized
isNotFrozen
{
Participant storage participantStats = participants[_participantAddress];
uint256 participantPendingEth = participantStats.pendingETH;
if(participantPendingEth == 0) {
if(_sentValue > 0) {
address(uint160(_participantAddress)).transfer(_sentValue);
}
return;
}
for (uint8 stageId = 0; stageId <= stageCount; stageId++) {
participantStats.stages[stageId].pendingETH = 0;
}
participantStats.pendingETH = 0;
canceledETH = canceledETH.add(participantPendingEth);
pendingETH = pendingETH.sub(participantPendingEth);
emit PendingContributionsCanceled(_participantAddress, participantPendingEth, uint32(participantStats.contributions));
emit TransferEvent(
uint8(TransferTypes.CONTRIBUTION_CANCELED),
_participantAddress,
participantPendingEth
);
address(uint160(_participantAddress)).transfer(participantPendingEth.add(_sentValue));
sanityCheckParticipant(_participantAddress);
sanityCheckProject();
}
function acceptContributions(address _participantAddress)
internal
isInitialized
isNotFrozen
isRunning
{
Participant storage participantStats = participants[_participantAddress];
if (participantStats.pendingETH == 0) {
return;
}
uint8 currentStage = getCurrentStage();
uint256 totalRefundedETH;
uint256 totalNewReservedTokens;
calcParticipantAllocation(_participantAddress);
if(participantStats.committedETH == 0) {
participantStats.firstContributionBlock = participantStats._lastBlock;
}
for (uint8 stageId = 0; stageId <= stageCount; stageId++) {
ParticipantStageDetails storage byStage = participantStats.stages[stageId];
if (byStage.pendingETH == 0) {
continue;
}
if(stageId < currentStage) {
participantStats.stages[currentStage].pendingETH = participantStats.stages[currentStage].pendingETH.add(byStage.pendingETH);
byStage.pendingETH = 0;
continue;
}
uint256 maxCommittableEth = committableEthAtStage(stageId, currentStage);
uint256 newlyCommittableEth = byStage.pendingETH;
uint256 returnEth = 0;
uint256 overflowEth = 0;
if (newlyCommittableEth > maxCommittableEth) {
overflowEth = newlyCommittableEth.sub(maxCommittableEth);
newlyCommittableEth = maxCommittableEth;
if (stageId == stageCount) {
returnEth = overflowEth;
totalRefundedETH = totalRefundedETH.add(returnEth);
} else {
participantStats.stages[stageId + 1].pendingETH = participantStats.stages[stageId + 1].pendingETH.add(overflowEth);
byStage.pendingETH = byStage.pendingETH.sub(overflowEth);
}
}
uint256 newTokenAmount = getTokenAmountForEthAtStage(
newlyCommittableEth, stageId
);
totalNewReservedTokens = totalNewReservedTokens.add(newTokenAmount);
participantStats._currentReservedTokens = participantStats._currentReservedTokens.add(newTokenAmount);
participantStats.reservedTokens = participantStats.reservedTokens.add(newTokenAmount);
participantStats.committedETH = participantStats.committedETH.add(newlyCommittableEth);
participantStats.pendingETH = participantStats.pendingETH.sub(newlyCommittableEth).sub(returnEth);
byStage.pendingETH = byStage.pendingETH.sub(newlyCommittableEth).sub(returnEth);
tokenSupply = tokenSupply.sub(newTokenAmount);
pendingETH = pendingETH.sub(newlyCommittableEth).sub(returnEth);
committedETH = committedETH.add(newlyCommittableEth);
_projectCurrentlyReservedETH = _projectCurrentlyReservedETH.add(newlyCommittableEth);
emit ContributionsAccepted(_participantAddress, newlyCommittableEth, newTokenAmount, stageId);
}
if (totalRefundedETH > 0) {
emit TransferEvent(uint8(TransferTypes.CONTRIBUTION_ACCEPTED_OVERFLOW), _participantAddress, totalRefundedETH);
address(uint160(_participantAddress)).transfer(totalRefundedETH);
}
IERC777(tokenAddress).send(_participantAddress, totalNewReservedTokens, "");
sanityCheckParticipant(_participantAddress);
sanityCheckProject();
}
function withdraw(address _participantAddress, uint256 _returnedTokenAmount)
internal
isInitialized
isNotFrozen
isRunning
{
Participant storage participantStats = participants[_participantAddress];
calcParticipantAllocation(_participantAddress);
require(_returnedTokenAmount > 0, 'You can not withdraw without sending tokens.');
require(participantStats._currentReservedTokens > 0 && participantStats.reservedTokens > 0, 'You can not withdraw, you have no locked tokens.');
uint256 returnedTokenAmount = _returnedTokenAmount;
uint256 overflowingTokenAmount;
uint256 returnEthAmount;
if (returnedTokenAmount > participantStats._currentReservedTokens) {
overflowingTokenAmount = returnedTokenAmount.sub(participantStats._currentReservedTokens);
returnedTokenAmount = participantStats._currentReservedTokens;
}
returnEthAmount = participantStats.committedETH.mul(
returnedTokenAmount.sub(1).mul(10 ** 20)
.div(participantStats.reservedTokens)
).div(10 ** 20);
participantStats.withdraws++;
participantStats._currentReservedTokens = participantStats._currentReservedTokens.sub(returnedTokenAmount);
participantStats.reservedTokens = participantStats.reservedTokens.sub(returnedTokenAmount);
participantStats.committedETH = participantStats.committedETH.sub(returnEthAmount);
tokenSupply = tokenSupply.add(returnedTokenAmount);
withdrawnETH = withdrawnETH.add(returnEthAmount);
committedETH = committedETH.sub(returnEthAmount);
_projectCurrentlyReservedETH = _projectCurrentlyReservedETH.sub(returnEthAmount);
if (overflowingTokenAmount > 0) {
bytes memory data;
emit TransferEvent(uint8(TransferTypes.PARTICIPANT_WITHDRAW_OVERFLOW), _participantAddress, overflowingTokenAmount);
IERC777(tokenAddress).send(_participantAddress, overflowingTokenAmount, data);
}
emit ParticipantWithdraw(_participantAddress, returnEthAmount, returnedTokenAmount, uint32(participantStats.withdraws));
emit TransferEvent(uint8(TransferTypes.PARTICIPANT_WITHDRAW), _participantAddress, returnEthAmount);
address(uint160(_participantAddress)).transfer(returnEthAmount);
sanityCheckParticipant(_participantAddress);
sanityCheckProject();
}
modifier onlyProjectAddress() {
require(msg.sender == projectAddress, "Only the project can call this method.");
_;
}
modifier onlyDeployingAddress() {
require(msg.sender == deployingAddress, "Only the deployer can call this method.");
_;
}
modifier onlyWhitelistingAddress() {
require(msg.sender == whitelistingAddress, "Only the whitelist controller can call this method.");
_;
}
modifier onlyFreezerAddress() {
require(msg.sender == freezerAddress, "Only the freezer address can call this method.");
_;
}
modifier onlyRescuerAddress() {
require(msg.sender == rescuerAddress, "Only the rescuer address can call this method.");
_;
}
modifier isInitialized() {
require(initialized == true, "Contract must be initialized.");
_;
}
modifier isNotInitialized() {
require(initialized == false, "Contract can not be initialized.");
_;
}
modifier isFrozen() {
require(frozen == true, "rICO has to be frozen!");
_;
}
modifier isNotFrozen() {
require(frozen == false, "rICO is frozen!");
_;
}
modifier isRunning() {
uint256 blockNumber = getCurrentEffectiveBlockNumber();
require(blockNumber >= commitPhaseStartBlock && blockNumber <= buyPhaseEndBlock, "Current block is outside the rICO period.");
_;
}
}
{
"compilationTarget": {
"ReversibleICO.sol": "ReversibleICO"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"participantAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"stageId","type":"uint8"}],"name":"ContributionsAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"freezerAddress","type":"address"},{"indexed":true,"internalType":"uint8","name":"stageId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"FreezerAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"participantAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"withdrawCount","type":"uint32"}],"name":"ParticipantWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"participantAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"contributionId","type":"uint32"},{"indexed":false,"internalType":"uint8","name":"stageId","type":"uint8"}],"name":"PendingContributionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"participantAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"contributionId","type":"uint32"}],"name":"PendingContributionsCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"projectAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"withdrawCount","type":"uint32"}],"name":"ProjectWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"freezerAddress","type":"address"},{"indexed":true,"internalType":"uint8","name":"stageId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"SecurityDisableEscapeHatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rescuerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint8","name":"stageId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"SecurityEscapeHatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"freezerAddress","type":"address"},{"indexed":true,"internalType":"uint8","name":"stageId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"SecurityFreeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"freezerAddress","type":"address"},{"indexed":true,"internalType":"uint8","name":"stageId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"SecurityUnfreeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"stageId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"tokenLimit","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"StageChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"typeId","type":"uint8"},{"indexed":true,"internalType":"address","name":"relatedAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"participantAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"pendingETH","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"contributions","type":"uint32"}],"name":"WhitelistApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"participantAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"pendingETH","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"contributions","type":"uint32"}],"name":"WhitelistRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"whitelistingAddress","type":"address"},{"indexed":true,"internalType":"uint8","name":"stageId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"effectiveBlockNumber","type":"uint256"}],"name":"WhitelistingAddressChanged","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"buyPhaseBlockCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"buyPhaseEndBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"buyPhaseStartBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_lastBlock","type":"uint256"}],"name":"calcUnlockedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"cancel","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"canceledETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newAddress","type":"address"}],"name":"changeFreezerAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint8","name":"_stageId","type":"uint8"},{"internalType":"uint256","name":"_tokenLimit","type":"uint256"},{"internalType":"uint256","name":"_tokenPrice","type":"uint256"}],"name":"changeStage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_newAddress","type":"address"}],"name":"changeWhitelistingAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"commit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"commitPhaseBlockCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"commitPhaseEndBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"commitPhasePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"commitPhaseStartBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint8","name":"_stageId","type":"uint8"},{"internalType":"uint8","name":"_currentStage","type":"uint8"}],"name":"committableEthAtStage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"committedETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deployingAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"disableEscapeHatch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"escapeHatch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"freeze","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"freezeStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"freezerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"frozenPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAvailableProjectETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAvailableTokenAtCurrentStage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentEffectiveBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStage","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_tokenAmount","type":"uint256"},{"internalType":"uint8","name":"_stageId","type":"uint8"}],"name":"getEthAmountForTokensAtStage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_participantAddress","type":"address"}],"name":"getParticipantReservedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_participantAddress","type":"address"}],"name":"getParticipantUnlockedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint8","name":"_stageId","type":"uint8"}],"name":"getPriceAtStage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_tokenLimit","type":"uint256"}],"name":"getPriceForTokenLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_tokenLimit","type":"uint256"}],"name":"getStageByTokenLimit","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"_ethAmount","type":"uint256"},{"internalType":"uint8","name":"_stageId","type":"uint8"}],"name":"getTokenAmountForEthAtStage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getUnlockedProjectETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_whitelistingAddress","type":"address"},{"internalType":"address","name":"_freezerAddress","type":"address"},{"internalType":"address","name":"_rescuerAddress","type":"address"},{"internalType":"address","name":"_projectAddress","type":"address"},{"internalType":"uint256","name":"_commitPhaseStartBlock","type":"uint256"},{"internalType":"uint256","name":"_buyPhaseStartBlock","type":"uint256"},{"internalType":"uint256","name":"_buyPhaseEndBlock","type":"uint256"},{"internalType":"uint256","name":"_initialPrice","type":"uint256"},{"internalType":"uint8","name":"_stageCount","type":"uint8"},{"internalType":"uint256","name":"_stageTokenLimitIncrease","type":"uint256"},{"internalType":"uint256","name":"_stagePriceIncrease","type":"uint256"}],"name":"init","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initialTokenSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxContribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minContribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"participantCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"participants","outputs":[{"internalType":"bool","name":"whitelisted","type":"bool"},{"internalType":"uint32","name":"contributions","type":"uint32"},{"internalType":"uint32","name":"withdraws","type":"uint32"},{"internalType":"uint256","name":"firstContributionBlock","type":"uint256"},{"internalType":"uint256","name":"reservedTokens","type":"uint256"},{"internalType":"uint256","name":"committedETH","type":"uint256"},{"internalType":"uint256","name":"pendingETH","type":"uint256"},{"internalType":"uint256","name":"_currentReservedTokens","type":"uint256"},{"internalType":"uint256","name":"_unlockedTokens","type":"uint256"},{"internalType":"uint256","name":"_lastBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"participantsById","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"projectAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"projectTokenWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_ethAmount","type":"uint256"}],"name":"projectWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"projectWithdrawCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"projectWithdrawnETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"rescuerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stageCount","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"stages","outputs":[{"internalType":"uint256","name":"tokenLimit","type":"uint256"},{"internalType":"uint256","name":"tokenPrice","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tokenSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"tokensReceived","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unfreeze","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"bool","name":"_approve","type":"bool"}],"name":"whitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"whitelistingAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"withdrawnETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]