Created
May 26, 2018 22:05
-
-
Save PhABC/81adefc59c00386f057fc82531baf98e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.24; | |
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; | |
import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; | |
import "openzeppelin-solidity/contracts/math/SafeMath.sol"; | |
/** | |
* @title Crowdsale | |
* @dev Crowdsale is a base contract for managing a token crowdsale, | |
* allowing investors to purchase tokens with ether. This contract implements | |
* such functionality in its most fundamental form and can be extended to provide additional | |
* functionality and/or custom behavior. | |
* The external interface represents the basic interface for purchasing tokens, and conform | |
* the base architecture for crowdsales. They are *not* intended to be modified / overriden. | |
* The internal interface conforms the extensible and modifiable surface of crowdsales. Override | |
* the methods to add functionality. Consider using 'super' where appropiate to concatenate | |
* behavior. | |
*/ | |
contract TokenSale_GasTokenFactory is Ownable { | |
using SafeMath for uint256; | |
// The token being sold | |
ERC20 public token; | |
// Address where funds are collected | |
address public wallet; | |
// How many token units a buyer gets per wei | |
uint256 public rate; | |
// Amount of wei raised | |
uint256 public weiRaised; | |
// Finalized sale | |
bool finalized = false; | |
// IndividuallyCappedCrowdsale mappings | |
mapping(address => uint256) public contributions; | |
mapping(address => uint256) public caps; | |
/** | |
* @param _rate Number of token units a buyer gets per wei | |
* @param _wallet Address where collected funds will be forwarded to | |
* @param _token Address of the token being sold | |
*/ | |
constructor(uint256 _rate, address _wallet, ERC20 _token) public { | |
require(_rate > 0); | |
require(_wallet != address(0)); | |
require(_token != address(0)); | |
rate = _rate; | |
wallet = _wallet; | |
token = _token; | |
} | |
// ----------------------------------------- | |
// Crowdsale external interface | |
// ----------------------------------------- | |
/** | |
* @dev fallback function ***DO NOT OVERRIDE*** | |
*/ | |
function () external payable { | |
buyTokens(msg.sender); | |
} | |
/** | |
* @dev low level token purchase ***DO NOT OVERRIDE*** | |
* @param _beneficiary Address performing the token purchase | |
*/ | |
function buyTokens(address _beneficiary) public payable { | |
// How many weis are sent for purchase | |
uint256 weiAmount = msg.value; | |
// Verify that the purchase is valid | |
_preValidatePurchase(_beneficiary, weiAmount); | |
// Calculate token amount to be created | |
uint256 tokens = weiAmount.mul(rate); | |
// Update fund raised | |
weiRaised = weiRaised.add(weiAmount); | |
// Transfer tokens to _beneficiary | |
token.transfer(_beneficiary, tokens); | |
// Increase contribution by _benificiary | |
contributions[_beneficiary] = contributions[_beneficiary].add(weiAmount); | |
// Transfer funds to fund wallet | |
wallet.transfer(msg.value); | |
} | |
/** | |
* @dev Owner can finalize sell, where tokens can't be sold anymore | |
*/ | |
function finalizeSale() onlyOwner public { | |
require(!finalized); | |
finalized = true; | |
} | |
// ----------------------------------------- | |
// Internal interface (extensible) | |
// ----------------------------------------- | |
/** | |
* @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations. | |
* @param _beneficiary Address performing the token purchase | |
* @param _weiAmount Value in wei involved in the purchase | |
*/ | |
function _preValidatePurchase( | |
address _beneficiary, | |
uint256 _weiAmount | |
) | |
internal | |
{ | |
// require(isWhitelisted(_benificiary)); Is not required since cap acts as whitelist | |
require(contributions[_beneficiary].add(_weiAmount) <= caps[_beneficiary]); | |
require(_beneficiary != address(0)); | |
require(_weiAmount != 0); | |
require(!finalized); | |
} | |
// ----------------------------------------- | |
// IndividuallyCappedCrowdsale Functions | |
// ----------------------------------------- | |
/** | |
* @dev Sets a specific user's maximum contribution | |
* @param _beneficiary Address to be capped | |
* @param _cap Wei limit for individual contribution | |
*/ | |
function setUserCap(address _beneficiary, uint256 _cap) external onlyOwner { | |
caps[_beneficiary] = _cap; | |
// Save user info to free later | |
_mintGasToken(_beneficiary); | |
} | |
// ----------------------------------------- | |
// GasTokenFactory Functions | |
// ----------------------------------------- | |
// We start our storage at this location. The EVM word at this location | |
// contains the number of stored words. The stored words follow at | |
// locations (STORAGE_LOCATION_ARRAY+1), (STORAGE_LOCATION_ARRAY+2), ... | |
uint256 constant STORAGE_LOCATION_ARRAY = 0xDEADBEEF; | |
/** | |
* @dev Keeps track of all the storage slots that can be freed, where gas tokens are kept in contract | |
* @param _user Address that is associated with mappings that can be freed | |
*/ | |
function _mintGasToken(address _user) internal { | |
// Loading storage location array in memory to use with assembly | |
uint256 storage_location_array = STORAGE_LOCATION_ARRAY; | |
// Read gasToken supply | |
uint256 supply; | |
assembly { supply := sload(storage_location_array) } | |
// Index where to store info | |
uint256 index = storage_location_array + supply + 1; | |
// Store user info to free storage space | |
assembly { sstore(index, _user) } | |
// Update gasToken supply | |
assembly { sstore(storage_location_array, add(supply, 1)) } | |
} | |
/** | |
* @dev Allow anyone to free some of the storage | |
* @param _amount Amount of storage slots you want to free | |
* | |
*/ | |
function freeStorage(uint256 _amount) public { | |
//require(finalized, 'Sale not finalized'); | |
// Address to destroy | |
address user; | |
// Loading storage location array in memory to use with assembly | |
uint256 storage_location_array = STORAGE_LOCATION_ARRAY; | |
// Read gasToken supply | |
uint256 supply; | |
assembly { supply := sload(storage_location_array) } | |
// Clear memory locations in interval [l, r] | |
uint256 l = storage_location_array + supply - _amount + 1; | |
uint256 r = storage_location_array + supply; | |
// Empty storage | |
for (uint256 i = l; i <= r; i++) { | |
// Loading current user address | |
assembly { user := sload(i) } | |
// Empty caps and contributions | |
caps[user] = 0; | |
contributions[user] = 0; | |
// Burn gasToken associated with user | |
assembly { sstore(i, 0) } | |
} | |
// Update tokenGas supply | |
assembly { | |
sstore(storage_location_array, sub(supply, _amount)) | |
} | |
} | |
// totalSupply is the number of words we have in storage | |
function totalGasTokenSupply() public constant returns (uint256 supply) { | |
uint256 storage_location_array = STORAGE_LOCATION_ARRAY; | |
assembly { | |
supply := sload(storage_location_array) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment