Skip to content

Instantly share code, notes, and snippets.

@PhABC
Created May 26, 2018 22:05
Show Gist options
  • Save PhABC/81adefc59c00386f057fc82531baf98e to your computer and use it in GitHub Desktop.
Save PhABC/81adefc59c00386f057fc82531baf98e to your computer and use it in GitHub Desktop.
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