Skip to content

Instantly share code, notes, and snippets.

@kissarat
Created October 18, 2018 10:15
Show Gist options
  • Save kissarat/17cb948fd35bb40f643b1772f1073194 to your computer and use it in GitHub Desktop.
Save kissarat/17cb948fd35bb40f643b1772f1073194 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.24;
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
library SafeMath {
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a / _b;
}
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) internal balances;
uint256 internal totalSupply_;
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
function transfer(address _to, uint256 _value) public returns (bool) {
require(_value <= balances[msg.sender]);
require(_to != address(0));
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
function balanceOf(address _owner) public view returns (uint256) {
return balances[_owner];
}
}
contract ERC20 is ERC20Basic {
function allowance(address _owner, address _spender)
public view returns (uint256);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
contract StandardToken is ERC20, BasicToken {
mapping(address => mapping(address => uint256)) internal allowed;
function transferFrom(
address _from,
address _to,
uint256 _value
)
public
returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(
address _owner,
address _spender
)
public
view
returns (uint256)
{
return allowed[_owner][_spender];
}
function increaseApproval(
address _spender,
uint256 _addedValue
)
public
returns (bool)
{
allowed[msg.sender][_spender] = (
allowed[msg.sender][_spender].add(_addedValue));
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval(
address _spender,
uint256 _subtractedValue
)
public
returns (bool)
{
uint256 oldValue = allowed[msg.sender][_spender];
if (_subtractedValue >= oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
modifier hasMintPermission() {
require(msg.sender == owner);
_;
}
function mint(
address _to,
uint256 _amount
)
public
hasMintPermission
canMint
returns (bool)
{
totalSupply_ = totalSupply_.add(_amount);
balances[_to] = balances[_to].add(_amount);
emit Mint(_to, _amount);
emit Transfer(address(0), _to, _amount);
return true;
}
function finishMinting() public onlyOwner canMint returns (bool) {
mintingFinished = true;
emit MintFinished();
return true;
}
}
contract DetailedERC20 is ERC20 {
string public name;
string public symbol;
uint8 public decimals;
constructor(string _name, string _symbol, uint8 _decimals) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
}
}
contract WAS_Token is MintableToken, DetailedERC20 {
uint256 public totalSupplyLimit = 260260676;
constructor() DetailedERC20("Wasi", "WAS", 0) public {
}
function burnUnsoldTokens() public onlyOwner {
balances[owner] = 0;
}
}
contract WAS_CrowdsaleReservations {
using SafeMath for uint256;
uint256 public reserveTokensTeamPercent = 5; // 13013033 tokens
uint256 public reservedTokensTeam;
uint256 public tokensCrowdsalePurchased;
uint256 public reservedTokensCrowdsalePurchase;
constructor(uint256 _totalSupply) public {
calculateReservations(_totalSupply);
}
function calculateReservations(uint256 _totalSupply) private {
reservedTokensTeam = _totalSupply.mul(reserveTokensTeamPercent).div(100);
reservedTokensCrowdsalePurchase = 50 * (10 ** 6);
// 50m
}
}
library SafeERC20 {
function safeTransfer(
ERC20Basic _token,
address _to,
uint256 _value
)
internal
{
require(_token.transfer(_to, _value));
}
function safeTransferFrom(
ERC20 _token,
address _from,
address _to,
uint256 _value
)
internal
{
require(_token.transferFrom(_from, _to, _value));
}
function safeApprove(
ERC20 _token,
address _spender,
uint256 _value
)
internal
{
require(_token.approve(_spender, _value));
}
}
contract Crowdsale {
using SafeMath for uint256;
using SafeERC20 for ERC20;
ERC20 public token;
address public wallet;
uint256 public rate;
uint256 public weiRaised;
event TokenPurchase(
address indexed purchaser,
address indexed beneficiary,
uint256 value,
uint256 amount
);
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;
}
function() external payable {
buyTokens(msg.sender);
}
function buyTokens(address _beneficiary) public payable {
uint256 weiAmount = msg.value;
_preValidatePurchase(_beneficiary, weiAmount);
uint256 tokens = _getTokenAmount(weiAmount);
weiRaised = weiRaised.add(weiAmount);
_processPurchase(_beneficiary, tokens);
emit TokenPurchase(
msg.sender,
_beneficiary,
weiAmount,
tokens
);
_updatePurchasingState(_beneficiary, weiAmount);
_forwardFunds();
_postValidatePurchase(_beneficiary, weiAmount);
}
function _preValidatePurchase(
address _beneficiary,
uint256 _weiAmount
)
internal
{
require(_beneficiary != address(0));
require(_weiAmount != 0);
}
function _postValidatePurchase(
address _beneficiary,
uint256 _weiAmount
)
internal
{
}
function _deliverTokens(
address _beneficiary,
uint256 _tokenAmount
)
internal
{
token.safeTransfer(_beneficiary, _tokenAmount);
}
function _processPurchase(
address _beneficiary,
uint256 _tokenAmount
)
internal
{
_deliverTokens(_beneficiary, _tokenAmount);
}
function _updatePurchasingState(
address _beneficiary,
uint256 _weiAmount
)
internal
{
}
function _getTokenAmount(uint256 _weiAmount)
internal view returns (uint256)
{
return _weiAmount.mul(rate);
}
function _forwardFunds() internal {
wallet.transfer(msg.value);
}
}
contract TimedCrowdsale is Crowdsale {
using SafeMath for uint256;
uint256 public openingTime;
uint256 public closingTime;
modifier onlyWhileOpen {
require(block.timestamp >= openingTime && block.timestamp <= closingTime);
_;
}
constructor(uint256 _openingTime, uint256 _closingTime) public {
require(_openingTime >= block.timestamp);
require(_closingTime >= _openingTime);
openingTime = _openingTime;
closingTime = _closingTime;
}
function hasClosed() public view returns (bool) {
return block.timestamp > closingTime;
}
function _preValidatePurchase(
address _beneficiary,
uint256 _weiAmount
)
internal
onlyWhileOpen
{
super._preValidatePurchase(_beneficiary, _weiAmount);
}
}
contract FinalizableCrowdsale is Ownable, TimedCrowdsale {
using SafeMath for uint256;
bool public isFinalized = false;
event Finalized();
function finalize() public onlyOwner {
require(!isFinalized);
require(hasClosed());
finalization();
emit Finalized();
isFinalized = true;
}
function finalization() internal {
}
}
contract WAS_Crowdsale_Stages is FinalizableCrowdsale, WAS_CrowdsaleReservations {
uint256[] rateETH;
uint256[] openingTimings;
uint256[] closingTimings;
uint256[] stagePurchaseTokensMinimum;
modifier onlyWhileOpen {
bool stageRunning;
uint256 stageIdx;
(stageRunning, stageIdx) = currentStage();
require(stageRunning, "no stage is currently running");
_;
}
constructor(uint256[] _rateETH, uint256[] _openingTimings, uint256[] _closingTimings)
TimedCrowdsale(_openingTimings[0], _closingTimings[_closingTimings.length - 1])
public {
validateRates(_rateETH);
validateOpeningAndClosingTimings(_openingTimings, _closingTimings);
rateETH = _rateETH;
openingTimings = _openingTimings;
closingTimings = _closingTimings;
stagePurchaseTokensMinimum = [0, 100];
}
function hasOpened() public view returns (bool) {
return now >= openingTime;
}
function currentRateETH() public view returns (uint256) {
bool stageRunning;
uint256 stageIdx;
(stageRunning, stageIdx) = currentStage();
require(stageRunning, "no stage is currently running");
return rateETH[stageIdx];
}
function currentDiscount(uint256 _tokenPurchasedAmount) public view returns (uint256) {
bool stageRunning;
uint256 stageIdx;
(stageRunning, stageIdx) = currentStage();
require(stageRunning, "no stage is currently running");
return discountPercentForStage(stageIdx, _tokenPurchasedAmount);
}
function currentStage() public view returns (bool, uint256) {
for (uint256 i = 0; i < closingTimings.length; i ++) {
if (block.timestamp <= closingTimings[i] && block.timestamp >= openingTimings[i]) {
return (true, i);
}
}
return (false, 0);
}
function updateStageRateETH(uint256 _stage, uint256 _rateETH) public onlyOwner {
rateETH[_stage] = _rateETH;
}
function updateOpeningAndClosingTimings(uint256[] _openingTimings, uint256[] _closingTimings) public onlyOwner {
validateOpeningAndClosingTimings(_openingTimings, _closingTimings);
openingTimings = _openingTimings;
closingTimings = _closingTimings;
}
function validateRates(uint256[] _rateETH) private pure {
for (uint256 i = 0; i < _rateETH.length; i ++) {
require(_rateETH[i] > 0, "rate must be > 0");
}
}
function validateOpeningAndClosingTimings(uint256[] _openingTimings, uint256[] _closingTimings) private view {
require(_openingTimings.length == _closingTimings.length, "timings length differs");
require(_openingTimings[0] > block.timestamp, "should open in future");
for (uint256 i = 0; i < _openingTimings.length; i ++) {
require(_closingTimings[i] > _openingTimings[i], "closing time of stage must be > opening time of same stage");
if (i > 0) {
require(_openingTimings[i] > _openingTimings[i - 1], "opening time must be > than previous opening time");
}
}
}
function discountPercentForStage(uint256 _stage, uint256 _tokenPurchasedAmount) private pure returns (uint256) {
if (_stage == 0) {
return 30;
} else if (_stage == 1) {
if (_tokenPurchasedAmount >= 15000) {
return 10;
} else if (_tokenPurchasedAmount >= 10000) {
return 7;
} else if (_tokenPurchasedAmount >= 5000) {
return 5;
}
}
return 0;
}
}
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
modifier whenNotPaused() {
require(!paused);
_;
}
modifier whenPaused() {
require(paused);
_;
}
function pause() public onlyOwner whenNotPaused {
paused = true;
emit Pause();
}
function unpause() public onlyOwner whenPaused {
paused = false;
emit Unpause();
}
}
library Roles {
struct Role {
mapping(address => bool) bearer;
}
function add(Role storage _role, address _addr)
internal
{
_role.bearer[_addr] = true;
}
function remove(Role storage _role, address _addr)
internal
{
_role.bearer[_addr] = false;
}
function check(Role storage _role, address _addr)
internal
view
{
require(has(_role, _addr));
}
function has(Role storage _role, address _addr)
internal
view
returns (bool)
{
return _role.bearer[_addr];
}
}
contract RBAC {
using Roles for Roles.Role;
mapping(string => Roles.Role) private roles;
event RoleAdded(address indexed operator, string role);
event RoleRemoved(address indexed operator, string role);
function checkRole(address _operator, string _role)
public
view
{
roles[_role].check(_operator);
}
function hasRole(address _operator, string _role)
public
view
returns (bool)
{
return roles[_role].has(_operator);
}
function addRole(address _operator, string _role)
internal
{
roles[_role].add(_operator);
emit RoleAdded(_operator, _role);
}
function removeRole(address _operator, string _role)
internal
{
roles[_role].remove(_operator);
emit RoleRemoved(_operator, _role);
}
modifier onlyRole(string _role)
{
checkRole(msg.sender, _role);
_;
}
}
contract Whitelist is Ownable, RBAC {
string public constant ROLE_WHITELISTED = "whitelist";
modifier onlyIfWhitelisted(address _operator) {
checkRole(_operator, ROLE_WHITELISTED);
_;
}
function addAddressToWhitelist(address _operator)
public
onlyOwner
{
addRole(_operator, ROLE_WHITELISTED);
}
function whitelist(address _operator)
public
view
returns (bool)
{
return hasRole(_operator, ROLE_WHITELISTED);
}
function addAddressesToWhitelist(address[] _operators)
public
onlyOwner
{
for (uint256 i = 0; i < _operators.length; i++) {
addAddressToWhitelist(_operators[i]);
}
}
function removeAddressFromWhitelist(address _operator)
public
onlyOwner
{
removeRole(_operator, ROLE_WHITELISTED);
}
function removeAddressesFromWhitelist(address[] _operators)
public
onlyOwner
{
for (uint256 i = 0; i < _operators.length; i++) {
removeAddressFromWhitelist(_operators[i]);
}
}
}
contract WhitelistedCrowdsale is Whitelist, Crowdsale {
function _preValidatePurchase(
address _beneficiary,
uint256 _weiAmount
)
internal
onlyIfWhitelisted(_beneficiary)
{
super._preValidatePurchase(_beneficiary, _weiAmount);
}
}
contract Destructible is Ownable {
function destroy() public onlyOwner {
selfdestruct(owner);
}
function destroyAndSend(address _recipient) public onlyOwner {
selfdestruct(_recipient);
}
}
contract WAS_Crowdsale is WhitelistedCrowdsale, Destructible, Pausable, WAS_Crowdsale_Stages {
WAS_Token token;
constructor(address _wallet, ERC20 _token, uint256[] _rateETH, uint256[] _openingTimings, uint256[] _closingTimings)
Crowdsale(1, _wallet, _token)
WAS_Crowdsale_Stages(_rateETH, _openingTimings, _closingTimings)
WAS_CrowdsaleReservations(WAS_Token(_token).totalSupplyLimit())
public {
require(_token != address(0), "token address cannt be 0");
token = WAS_Token(_token);
}
function mintTotalSupplyAndTeam(address _teamAddress) public onlyOwner {
require(_teamAddress != address(0), "team address can not be 0");
require(reservedTokensTeam > 0, "team tokens can not be 0");
token.mint(_teamAddress, reservedTokensTeam);
uint256 purchaseTokens = token.totalSupplyLimit().sub(reservedTokensTeam);
token.mint(address(this), purchaseTokens);
token.finishMinting();
}
function manualTransfer(address _to, uint256 _tokenAmount) public onlyOwner {
bool stageRunning;
uint256 stageIdx;
(stageRunning, stageIdx) = currentStage();
require(stageRunning, "no stage is currently running");
require(stageIdx == 0, "manual transfer allowed during first stage only");
require(tokensCrowdsalePurchased.add(_tokenAmount) <= reservedTokensCrowdsalePurchase, "not enough tokens to manually transfer");
tokensCrowdsalePurchased = tokensCrowdsalePurchased.add(_tokenAmount);
token.transfer(_to, _tokenAmount);
}
function destroy() public onlyOwner {
require(hasClosed(), "crowdsale must be closed");
require(isFinalized, "crowdsale must be finalized");
selfdestruct(owner);
}
function destroyAndSend(address _recipient) public onlyOwner {
require(hasClosed(), "crowdsale must be closed");
require(isFinalized, "crowdsale must be finalized");
selfdestruct(_recipient);
}
function finalization() internal {
uint256 unpurchasedTokens = token.balanceOf(address(this));
token.transfer(owner, unpurchasedTokens);
super.finalization();
}
function _preValidatePurchase(
address _beneficiary,
uint256 _weiAmount
)
internal
whenNotPaused()
onlyWhileOpen()
{
super._preValidatePurchase(_beneficiary, _weiAmount);
}
function _getTokenAmount(uint256 _weiAmount)
internal view returns (uint256)
{
uint256 rateETH = currentRateETH();
uint256 tokens = _weiAmount.mul(rateETH).div(uint256(10 ** 18));
uint256 discount = currentDiscount(tokens);
if (discount > 0) {
tokens = tokens.add(tokens.mul(discount).div(100));
}
return tokens;
}
function _processPurchase(
address _beneficiary,
uint256 _tokenAmount
)
internal
{
bool stageRunning;
uint256 stageIdx;
(stageRunning, stageIdx) = currentStage();
require(stageRunning, "no stage is currently running");
require(_tokenAmount >= stagePurchaseTokensMinimum[stageIdx], "token amount is less than minimum for stage");
require(tokensCrowdsalePurchased.add(_tokenAmount) <= reservedTokensCrowdsalePurchase, "not enough tokens to purchase");
tokensCrowdsalePurchased = tokensCrowdsalePurchased.add(_tokenAmount);
super._processPurchase(_beneficiary, _tokenAmount);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment