Transaction Hash:
Block:
11863633 at Feb-15-2021 08:55:51 PM +UTC
Transaction Fee:
0.038802456 ETH
$99.92
Gas Used:
279,960 Gas / 138.6 Gwei
Emitted Events:
171 |
ReversibleICO.PendingContributionAdded( participantAddress=[Sender] 0x41d1b9deb85b56c61ad4e26559ee3843c5198e13, amount=7750000000000000000, contributionId=8, stageId=9 )
|
172 |
ReversibleICO.ContributionsAccepted( participantAddress=[Sender] 0x41d1b9deb85b56c61ad4e26559ee3843c5198e13, ethAmount=7750000000000000000, tokenAmount=3690476190476190476190, stageId=9 )
|
173 |
ReversibleICOToken.Sent( operator=[Receiver] ReversibleICO, from=[Receiver] ReversibleICO, to=[Sender] 0x41d1b9deb85b56c61ad4e26559ee3843c5198e13, amount=3690476190476190476190, data=0x, operatorData=0x )
|
174 |
ReversibleICOToken.Transfer( from=[Receiver] ReversibleICO, to=[Sender] 0x41d1b9deb85b56c61ad4e26559ee3843c5198e13, value=3690476190476190476190 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x41D1b9de...3C5198e13 |
9.086581792271449919 Eth
Nonce: 10
|
1.297779336271449919 Eth
Nonce: 11
| 7.788802456 | ||
0x5A0b54D5...D3E029c4c
Miner
| (Spark Pool) | 120.741718673390856052 Eth | 120.780521129390856052 Eth | 0.038802456 | |
0xA8b91968...5aec0be6D | |||||
0xE417b912...191b2CdF6 | (LUKSO: Reversible ICO) | 1,819.083951827471469967 Eth | 1,826.833951827471469967 Eth | 7.75 |
Execution Trace
ETH 7.75
ReversibleICO.CALL( )
ReversibleICOToken.send( recipient=0x41D1b9deb85B56C61ad4e26559ee3843C5198e13, amount=3690476190476190476190, data=0x )
-
ERC1820Registry.getInterfaceImplementer( _addr=0xE417b912F6cB6592ec2D71dbF6F2B48191b2CdF6, _interfaceHash=29DDB589B1FB5FC7CF394961C1ADF5F8C6454761ADF795E67FE149F658ABE895 ) => ( 0x0000000000000000000000000000000000000000 )
-
ReversibleICO.getParticipantReservedTokens( _participantAddress=0xE417b912F6cB6592ec2D71dbF6F2B48191b2CdF6 ) => ( 0 )
-
ERC1820Registry.getInterfaceImplementer( _addr=0x41D1b9deb85B56C61ad4e26559ee3843C5198e13, _interfaceHash=B281FC8C12954D22544DB45DE3159A39272895B169A852B314F9CC762E44C53B ) => ( 0x0000000000000000000000000000000000000000 )
-
[ReversibleICO (ln:436)]
commit[ReversibleICO (ln:446)]
getCurrentStage[ReversibleICO (ln:498)]
getStageByTokenLimit[ReversibleICO (ln:789)]
sub[ReversibleICO (ln:790)]
add[ReversibleICO (ln:502)]
add[ReversibleICO (ln:514)]
add[ReversibleICO (ln:515)]
add[ReversibleICO (ln:518)]
PendingContributionAdded[ReversibleICO (ln:520)]
acceptContributions[ReversibleICO (ln:529)]
getCurrentStage[ReversibleICO (ln:1036)]
getStageByTokenLimit[ReversibleICO (ln:789)]
sub[ReversibleICO (ln:790)]
calcParticipantAllocation[ReversibleICO (ln:1040)]
getParticipantUnlockedTokens[ReversibleICO (ln:964)]
add[ReversibleICO (ln:774)]
calcUnlockedAmount[ReversibleICO (ln:775)]
getCurrentEffectiveBlockNumber[ReversibleICO (ln:883)]
sub[ReversibleICO (ln:895)]
sub[ReversibleICO (ln:899)]
sub[ReversibleICO (ln:902)]
div[ReversibleICO (ln:904)]
mul[ReversibleICO (ln:904)]
div[ReversibleICO (ln:905)]
mul[ReversibleICO (ln:905)]
getParticipantReservedTokens[ReversibleICO (ln:965)]
sub[ReversibleICO (ln:765)]
calcUnlockedAmount[ReversibleICO (ln:766)]
getCurrentEffectiveBlockNumber[ReversibleICO (ln:883)]
sub[ReversibleICO (ln:895)]
sub[ReversibleICO (ln:899)]
sub[ReversibleICO (ln:902)]
div[ReversibleICO (ln:904)]
mul[ReversibleICO (ln:904)]
div[ReversibleICO (ln:905)]
mul[ReversibleICO (ln:905)]
getCurrentEffectiveBlockNumber[ReversibleICO (ln:968)]
calcProjectAllocation[ReversibleICO (ln:971)]
calcUnlockedAmount[ReversibleICO (ln:949)]
getCurrentEffectiveBlockNumber[ReversibleICO (ln:883)]
sub[ReversibleICO (ln:895)]
sub[ReversibleICO (ln:899)]
sub[ReversibleICO (ln:902)]
div[ReversibleICO (ln:904)]
mul[ReversibleICO (ln:904)]
div[ReversibleICO (ln:905)]
mul[ReversibleICO (ln:905)]
sub[ReversibleICO (ln:952)]
add[ReversibleICO (ln:953)]
getCurrentEffectiveBlockNumber[ReversibleICO (ln:954)]
sanityCheckProject[ReversibleICO (ln:956)]
add[ReversibleICO (ln:1059)]
committableEthAtStage[ReversibleICO (ln:1067)]
sub[ReversibleICO (ln:841)]
sub[ReversibleICO (ln:842)]
sub[ReversibleICO (ln:847)]
getEthAmountForTokensAtStage[ReversibleICO (ln:850)]
sub[ReversibleICO (ln:1075)]
add[ReversibleICO (ln:1081)]
add[ReversibleICO (ln:1085)]
sub[ReversibleICO (ln:1086)]
getTokenAmountForEthAtStage[ReversibleICO (ln:1091)]
add[ReversibleICO (ln:1095)]
add[ReversibleICO (ln:1098)]
add[ReversibleICO (ln:1099)]
add[ReversibleICO (ln:1100)]
sub[ReversibleICO (ln:1101)]
sub[ReversibleICO (ln:1101)]
sub[ReversibleICO (ln:1103)]
sub[ReversibleICO (ln:1103)]
sub[ReversibleICO (ln:1106)]
sub[ReversibleICO (ln:1107)]
sub[ReversibleICO (ln:1107)]
add[ReversibleICO (ln:1108)]
add[ReversibleICO (ln:1109)]
ContributionsAccepted[ReversibleICO (ln:1112)]
TransferEvent[ReversibleICO (ln:1117)]
transfer[ReversibleICO (ln:1118)]
send[ReversibleICO (ln:1123)]
sanityCheckParticipant[ReversibleICO (ln:1126)]
cancelPendingContributions[ReversibleICO (ln:453)]
transfer[ReversibleICO (ln:987)]
add[ReversibleICO (ln:1001)]
sub[ReversibleICO (ln:1002)]
PendingContributionsCanceled[ReversibleICO (ln:1005)]
TransferEvent[ReversibleICO (ln:1006)]
transfer[ReversibleICO (ln:1014)]
add[ReversibleICO (ln:1014)]
sanityCheckParticipant[ReversibleICO (ln:1017)]
File 1 of 3: ReversibleICO
File 2 of 3: ReversibleICOToken
File 3 of 3: ERC1820Registry
/* * 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 <[email protected]>, Marjorie Hernandez <[email protected]> * @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."); _; } }
File 2 of 3: ReversibleICOToken
/** *Submitted for verification at Etherscan.io on 2020-05-13 */ /* * source https://github.com/lukso-network/rICO-smart-contracts * @name LUKSO Token * @author Micky Socaci <[email protected]>, Fabian Vogelsteller <@frozeman> * @license Apachae 2.0 */ /** * @dev Implementation of the `IERC777` interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using `_mint`. * * Support for ERC20 is included in this contract, as specified by the EIP: both * the ERC777 and ERC20 interfaces can be safely used when interacting with it. * Both `IERC777.Sent` and `IERC20.Transfer` events are emitted on token * movements. * * Additionally, the `granularity` value is hard-coded to `1`, meaning that there * are no special restrictions in the amount of tokens that created, moved, or * destroyed. This makes integration with ERC20 applications seamless. */ pragma solidity ^0.5.0; 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 IERC777Sender { function tokensToSend( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external; } interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } 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; } } library Address { function isContract(address account) internal view returns (bool) { bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; assembly { codehash := extcodehash(account) } return (codehash != 0x0 && codehash != accountHash); } function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } } 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 ERC777 is IERC777, IERC20 { using SafeMath for uint256; using Address for address; IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); mapping(address => uint256) private _balances; uint256 private _totalSupply; string private _name; string private _symbol; bytes32 constant private TOKENS_SENDER_INTERFACE_HASH = 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895; bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH = 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b; address[] private _defaultOperatorsArray; mapping(address => bool) private _defaultOperators; mapping(address => mapping(address => bool)) private _operators; mapping(address => mapping(address => bool)) private _revokedDefaultOperators; mapping (address => mapping (address => uint256)) private _allowances; constructor( string memory name, string memory symbol, address[] memory defaultOperators ) public { _name = name; _symbol = symbol; _defaultOperatorsArray = defaultOperators; for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) { _defaultOperators[_defaultOperatorsArray[i]] = true; } _erc1820.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); _erc1820.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this)); } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public pure returns (uint8) { return 18; } function granularity() public view returns (uint256) { return 1; } function totalSupply() public view returns (uint256) { return _totalSupply; } function balanceOf(address tokenHolder) public view returns (uint256) { return _balances[tokenHolder]; } function send(address recipient, uint256 amount, bytes calldata data) external { _send(msg.sender, msg.sender, recipient, amount, data, "", true); } function transfer(address recipient, uint256 amount) external returns (bool) { require(recipient != address(0), "ERC777: transfer to the zero address"); address from = msg.sender; _callTokensToSend(from, from, recipient, amount, "", ""); _move(from, from, recipient, amount, "", ""); _callTokensReceived(from, from, recipient, amount, "", "", false); return true; } function burn(uint256 amount, bytes calldata data) external { _burn(msg.sender, msg.sender, amount, data, ""); } function isOperatorFor( address operator, address tokenHolder ) public view returns (bool) { return operator == tokenHolder || (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) || _operators[tokenHolder][operator]; } function authorizeOperator(address operator) external { require(msg.sender != operator, "ERC777: authorizing self as operator"); if (_defaultOperators[operator]) { delete _revokedDefaultOperators[msg.sender][operator]; } else { _operators[msg.sender][operator] = true; } emit AuthorizedOperator(operator, msg.sender); } function revokeOperator(address operator) external { require(operator != msg.sender, "ERC777: revoking self as operator"); if (_defaultOperators[operator]) { _revokedDefaultOperators[msg.sender][operator] = true; } else { delete _operators[msg.sender][operator]; } emit RevokedOperator(operator, msg.sender); } function defaultOperators() public view returns (address[] memory) { return _defaultOperatorsArray; } function operatorSend( address sender, address recipient, uint256 amount, bytes calldata data, bytes calldata operatorData ) external { require(isOperatorFor(msg.sender, sender), "ERC777: caller is not an operator for holder"); _send(msg.sender, sender, recipient, amount, data, operatorData, true); } function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external { require(isOperatorFor(msg.sender, account), "ERC777: caller is not an operator for holder"); _burn(msg.sender, account, amount, data, operatorData); } function allowance(address holder, address spender) public view returns (uint256) { return _allowances[holder][spender]; } function approve(address spender, uint256 value) external returns (bool) { address holder = msg.sender; _approve(holder, spender, value); return true; } function transferFrom(address holder, address recipient, uint256 amount) external returns (bool) { require(recipient != address(0), "ERC777: transfer to the zero address"); require(holder != address(0), "ERC777: transfer from the zero address"); address spender = msg.sender; _callTokensToSend(spender, holder, recipient, amount, "", ""); _move(spender, holder, recipient, amount, "", ""); _approve(holder, spender, _allowances[holder][spender].sub(amount)); _callTokensReceived(spender, holder, recipient, amount, "", "", false); return true; } function _mint( address operator, address account, uint256 amount, bytes memory userData, bytes memory operatorData ) internal { require(account != address(0), "ERC777: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true); emit Minted(operator, account, amount, userData, operatorData); emit Transfer(address(0), account, amount); } function _send( address operator, address from, address to, uint256 amount, bytes memory userData, bytes memory operatorData, bool requireReceptionAck ) private { require(from != address(0), "ERC777: send from the zero address"); require(to != address(0), "ERC777: send to the zero address"); _callTokensToSend(operator, from, to, amount, userData, operatorData); _move(operator, from, to, amount, userData, operatorData); _callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck); } function _burn( address operator, address from, uint256 amount, bytes memory data, bytes memory operatorData ) internal { require(from != address(0), "ERC777: burn from the zero address"); _callTokensToSend(operator, from, address(0), amount, data, operatorData); _totalSupply = _totalSupply.sub(amount); _balances[from] = _balances[from].sub(amount); emit Burned(operator, from, amount, data, operatorData); emit Transfer(from, address(0), amount); } function _move( address operator, address from, address to, uint256 amount, bytes memory userData, bytes memory operatorData ) internal { _balances[from] = _balances[from].sub(amount); _balances[to] = _balances[to].add(amount); emit Sent(operator, from, to, amount, userData, operatorData); emit Transfer(from, to, amount); } function _approve(address holder, address spender, uint256 value) private { require(spender != address(0), "ERC777: approve to the zero address"); _allowances[holder][spender] = value; emit Approval(holder, spender, value); } function _callTokensToSend( address operator, address from, address to, uint256 amount, bytes memory userData, bytes memory operatorData ) private { address implementer = _erc1820.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH); if (implementer != address(0)) { IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); } } function _callTokensReceived( address operator, address from, address to, uint256 amount, bytes memory userData, bytes memory operatorData, bool requireReceptionAck ) private { address implementer = _erc1820.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH); if (implementer != address(0)) { IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); } else if (requireReceptionAck) { require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient"); } } } interface ReversibleICO { function getParticipantReservedTokens(address) external view returns (uint256); } contract ReversibleICOToken is ERC777 { ReversibleICO public rICO; bool public frozen; bool public initialized; address public deployingAddress; address public tokenGenesisAddress; address public migrationAddress; address public freezerAddress; address public rescuerAddress; event SetRICOaddress(address indexed rICOAddress); event SetMigrationAddress(address indexed migrationAddress); event Frozen(address indexed freezerAddress); event Unfrozen(address indexed freezerAddress); event RemovedFreezer(address indexed freezerAddress); event ChangedRICO(address indexed rICOAddress, address indexed rescuerAddress); constructor( string memory name, string memory symbol, address[] memory _defaultOperators ) ERC777(name, symbol, _defaultOperators) public { deployingAddress = msg.sender; } function init( address _ricoAddress, address _freezerAddress, address _rescuerAddress, address _tokenGenesisAddress, uint256 _initialSupply ) public isNotInitialized onlyDeployingAddress { require(_freezerAddress != address(0), "_freezerAddress cannot be 0x"); require(_rescuerAddress != address(0), "_rescuerAddress cannot be 0x"); require(_tokenGenesisAddress != address(0), "_tokenGenesisAddress cannot be 0x"); tokenGenesisAddress = _tokenGenesisAddress; freezerAddress = _freezerAddress; rescuerAddress = _rescuerAddress; _mint(_tokenGenesisAddress, _tokenGenesisAddress, _initialSupply, "", ""); if(_ricoAddress != address(0)) { rICO = ReversibleICO(_ricoAddress); emit SetRICOaddress(_ricoAddress); } initialized = true; } function setRICOaddress(address _ricoAddress) public onlyTokenGenesisAddress { require(address(rICO) == address(0), "rICO address already set!"); require(_ricoAddress != address(0), "rICO address cannot be 0x."); rICO = ReversibleICO(_ricoAddress); emit SetRICOaddress(_ricoAddress); } function setMigrationAddress(address _migrationAddress) public onlyTokenGenesisAddress { migrationAddress = _migrationAddress; emit SetMigrationAddress(migrationAddress); } function removeFreezer() public onlyFreezerAddress isNotFrozen { freezerAddress = address(0); emit RemovedFreezer(freezerAddress); } function freeze() public onlyFreezerAddress { frozen = true; emit Frozen(freezerAddress); } function unfreeze() public onlyFreezerAddress { frozen = false; emit Unfrozen(freezerAddress); } function changeRICO(address _newRicoAddress) public onlyRescuerAddress isFrozen { rICO = ReversibleICO(_newRicoAddress); emit ChangedRICO(_newRicoAddress, rescuerAddress); } function getLockedBalance(address _owner) public view returns(uint256) { if(address(rICO) != address(0)) { return rICO.getParticipantReservedTokens(_owner); } else { return 0; } } function getUnlockedBalance(address _owner) public view returns(uint256) { uint256 balance = balanceOf(_owner); if(address(rICO) != address(0)) { uint256 locked = rICO.getParticipantReservedTokens(_owner); if(balance > 0 && locked > 0) { if(balance >= locked) { return balance.sub(locked); } else { return 0; } } } return balance; } function _move( address _operator, address _from, address _to, uint256 _amount, bytes memory _userData, bytes memory _operatorData ) internal isNotFrozen isInitialized { if( _to == address(rICO) || _to == migrationAddress ) { require(_amount <= balanceOf(_from), "Sending failed: Insufficient funds"); } else { require(_amount <= getUnlockedBalance(_from), "Sending failed: Insufficient funds"); } ERC777._move(_operator, _from, _to, _amount, _userData, _operatorData); } function _burn( address _operator, address _from, uint256 _amount, bytes memory _data, bytes memory _operatorData ) internal isNotFrozen isInitialized { require(_amount <= getUnlockedBalance(_from), "Burning failed: Insufficient funds"); ERC777._burn(_operator, _from, _amount, _data, _operatorData); } modifier onlyDeployingAddress() { require(msg.sender == deployingAddress, "Only the deployer can call this method."); _; } modifier onlyTokenGenesisAddress() { require(msg.sender == tokenGenesisAddress, "Only the tokenGenesisAddress 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 is already initialized."); _; } modifier isFrozen() { require(frozen == true, "Token contract not frozen."); _; } modifier isNotFrozen() { require(frozen == false, "Token contract is frozen!"); _; } }
File 3 of 3: ERC1820Registry
/* ERC1820 Pseudo-introspection Registry Contract * This standard defines a universal registry smart contract where any address (contract or regular account) can * register which interface it supports and which smart contract is responsible for its implementation. * * Written in 2019 by Jordi Baylina and Jacques Dafflon * * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to * this software to the public domain worldwide. This software is distributed without any warranty. * * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see * <http://creativecommons.org/publicdomain/zero/1.0/>. * * ███████╗██████╗ ██████╗ ██╗ █████╗ ██████╗ ██████╗ * ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗ * █████╗ ██████╔╝██║ ╚██║╚█████╔╝ █████╔╝██║██╔██║ * ██╔══╝ ██╔══██╗██║ ██║██╔══██╗██╔═══╝ ████╔╝██║ * ███████╗██║ ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝ * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝ * * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗ * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝ * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝ * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝ * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║ * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ * */ pragma solidity 0.5.3; // IV is value needed to have a vanity address starting with '0x1820'. // IV: 53759 /// @dev The interface a contract MUST implement if it is the implementer of /// some (other) interface for any address other than itself. interface ERC1820ImplementerInterface { /// @notice Indicates whether the contract implements the interface 'interfaceHash' for the address 'addr' or not. /// @param interfaceHash keccak256 hash of the name of the interface /// @param addr Address for which the contract will implement the interface /// @return ERC1820_ACCEPT_MAGIC only if the contract implements 'interfaceHash' for the address 'addr'. function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); } /// @title ERC1820 Pseudo-introspection Registry Contract /// @author Jordi Baylina and Jacques Dafflon /// @notice This contract is the official implementation of the ERC1820 Registry. /// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820 contract ERC1820Registry { /// @notice ERC165 Invalid ID. bytes4 constant internal INVALID_ID = 0xffffffff; /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`). bytes4 constant internal ERC165ID = 0x01ffc9a7; /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address. bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC")); /// @notice mapping from addresses and interface hashes to their implementers. mapping(address => mapping(bytes32 => address)) internal interfaces; /// @notice mapping from addresses to their manager. mapping(address => address) internal managers; /// @notice flag for each address and erc165 interface to indicate if it is cached. mapping(address => mapping(bytes4 => bool)) internal erc165Cached; /// @notice Indicates a contract is the 'implementer' of 'interfaceHash' for 'addr'. event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer); /// @notice Indicates 'newManager' is the address of the new manager for 'addr'. event ManagerChanged(address indexed addr, address indexed newManager); /// @notice Query if an address implements an interface and through which contract. /// @param _addr Address being queried for the implementer of an interface. /// (If '_addr' is the zero address then 'msg.sender' is assumed.) /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. /// @return The address of the contract which implements the interface '_interfaceHash' for '_addr' /// or '0' if '_addr' did not register an implementer for this interface. function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) { address addr = _addr == address(0) ? msg.sender : _addr; if (isERC165Interface(_interfaceHash)) { bytes4 erc165InterfaceHash = bytes4(_interfaceHash); return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0); } return interfaces[addr][_interfaceHash]; } /// @notice Sets the contract which implements a specific interface for an address. /// Only the manager defined for that address can set it. /// (Each address is the manager for itself until it sets a new manager.) /// @param _addr Address for which to set the interface. /// (If '_addr' is the zero address then 'msg.sender' is assumed.) /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. /// @param _implementer Contract address implementing '_interfaceHash' for '_addr'. function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external { address addr = _addr == address(0) ? msg.sender : _addr; require(getManager(addr) == msg.sender, "Not the manager"); require(!isERC165Interface(_interfaceHash), "Must not be an ERC165 hash"); if (_implementer != address(0) && _implementer != msg.sender) { require( ERC1820ImplementerInterface(_implementer) .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC, "Does not implement the interface" ); } interfaces[addr][_interfaceHash] = _implementer; emit InterfaceImplementerSet(addr, _interfaceHash, _implementer); } /// @notice Sets '_newManager' as manager for '_addr'. /// The new manager will be able to call 'setInterfaceImplementer' for '_addr'. /// @param _addr Address for which to set the new manager. /// @param _newManager Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.) function setManager(address _addr, address _newManager) external { require(getManager(_addr) == msg.sender, "Not the manager"); managers[_addr] = _newManager == _addr ? address(0) : _newManager; emit ManagerChanged(_addr, _newManager); } /// @notice Get the manager of an address. /// @param _addr Address for which to return the manager. /// @return Address of the manager for a given address. function getManager(address _addr) public view returns(address) { // By default the manager of an address is the same address if (managers[_addr] == address(0)) { return _addr; } else { return managers[_addr]; } } /// @notice Compute the keccak256 hash of an interface given its name. /// @param _interfaceName Name of the interface. /// @return The keccak256 hash of an interface name. function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) { return keccak256(abi.encodePacked(_interfaceName)); } /* --- ERC165 Related Functions --- */ /* --- Developed in collaboration with William Entriken. --- */ /// @notice Updates the cache with whether the contract implements an ERC165 interface or not. /// @param _contract Address of the contract for which to update the cache. /// @param _interfaceId ERC165 interface for which to update the cache. function updateERC165Cache(address _contract, bytes4 _interfaceId) external { interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache( _contract, _interfaceId) ? _contract : address(0); erc165Cached[_contract][_interfaceId] = true; } /// @notice Checks whether a contract implements an ERC165 interface or not. // If the result is not cached a direct lookup on the contract address is performed. // If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling // 'updateERC165Cache' with the contract address. /// @param _contract Address of the contract to check. /// @param _interfaceId ERC165 interface to check. /// @return True if '_contract' implements '_interfaceId', false otherwise. function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) { if (!erc165Cached[_contract][_interfaceId]) { return implementsERC165InterfaceNoCache(_contract, _interfaceId); } return interfaces[_contract][_interfaceId] == _contract; } /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. /// @param _contract Address of the contract to check. /// @param _interfaceId ERC165 interface to check. /// @return True if '_contract' implements '_interfaceId', false otherwise. function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) { uint256 success; uint256 result; (success, result) = noThrowCall(_contract, ERC165ID); if (success == 0 || result == 0) { return false; } (success, result) = noThrowCall(_contract, INVALID_ID); if (success == 0 || result != 0) { return false; } (success, result) = noThrowCall(_contract, _interfaceId); if (success == 1 && result == 1) { return true; } return false; } /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not. /// @param _interfaceHash The hash to check. /// @return True if '_interfaceHash' is an ERC165 interface (ending with 28 zeroes), false otherwise. function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) { return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0; } /// @dev Make a call on a contract without throwing if the function does not exist. function noThrowCall(address _contract, bytes4 _interfaceId) internal view returns (uint256 success, uint256 result) { bytes4 erc165ID = ERC165ID; assembly { let x := mload(0x40) // Find empty storage location using "free memory pointer" mstore(x, erc165ID) // Place signature at beginning of empty storage mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature success := staticcall( 30000, // 30k gas _contract, // To addr x, // Inputs are stored at location x 0x24, // Inputs are 36 (4 + 32) bytes long x, // Store output over input (saves space) 0x20 // Outputs are 32 bytes long ) result := mload(x) // Load the result } } }