Merge pull request #283 from OpenZeppelin/crowdsale
Add Crowdsale contracts
This commit is contained in:
33
contracts/crowdsale/CappedCrowdsale.sol
Normal file
33
contracts/crowdsale/CappedCrowdsale.sol
Normal file
@ -0,0 +1,33 @@
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import '../SafeMath.sol';
|
||||
import './Crowdsale.sol';
|
||||
|
||||
/**
|
||||
* @title CappedCrowdsale
|
||||
* @dev Extension of Crowsdale with a max amount of funds raised
|
||||
*/
|
||||
contract CappedCrowdsale is Crowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
uint256 public cap;
|
||||
|
||||
function CappedCrowdsale(uint256 _cap) {
|
||||
cap = _cap;
|
||||
}
|
||||
|
||||
// overriding Crowdsale#validPurchase to add extra cap logic
|
||||
// @return true if investors can buy at the moment
|
||||
function validPurchase() internal constant returns (bool) {
|
||||
bool withinCap = weiRaised.add(msg.value) <= cap;
|
||||
return super.validPurchase() && withinCap;
|
||||
}
|
||||
|
||||
// overriding Crowdsale#hasEnded to add cap logic
|
||||
// @return true if crowdsale event has ended
|
||||
function hasEnded() public constant returns (bool) {
|
||||
bool capReached = weiRaised >= cap;
|
||||
return super.hasEnded() || capReached;
|
||||
}
|
||||
|
||||
}
|
||||
108
contracts/crowdsale/Crowdsale.sol
Normal file
108
contracts/crowdsale/Crowdsale.sol
Normal file
@ -0,0 +1,108 @@
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import '../token/MintableToken.sol';
|
||||
import '../SafeMath.sol';
|
||||
|
||||
/**
|
||||
* @title Crowdsale
|
||||
* @dev Crowdsale is a base contract for managing a token crowdsale.
|
||||
* Crowdsales have a start and end block, where investors can make
|
||||
* token purchases and the crowdsale will assign them tokens based
|
||||
* on a token per ETH rate. Funds collected are forwarded to a wallet
|
||||
* as they arrive.
|
||||
*/
|
||||
contract Crowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// The token being sold
|
||||
MintableToken public token;
|
||||
|
||||
// start and end block where investments are allowed (both inclusive)
|
||||
uint256 public startBlock;
|
||||
uint256 public endBlock;
|
||||
|
||||
// address where funds are collected
|
||||
address public wallet;
|
||||
|
||||
// how many token units a buyer gets per wei
|
||||
uint256 public rate;
|
||||
|
||||
// amount of raised money in wei
|
||||
uint256 public weiRaised;
|
||||
|
||||
/**
|
||||
* event for token purchase logging
|
||||
* @param purchaser who paid for the tokens
|
||||
* @param beneficiary who got the tokens
|
||||
* @param value weis paid for purchase
|
||||
* @param amount amount of tokens purchased
|
||||
*/
|
||||
event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
|
||||
|
||||
|
||||
function Crowdsale(uint256 _startBlock, uint256 _endBlock, uint256 _rate, address _wallet) {
|
||||
require(_startBlock >= block.number);
|
||||
require(_endBlock >= _startBlock);
|
||||
require(_rate > 0);
|
||||
require(_wallet != 0x0);
|
||||
|
||||
token = createTokenContract();
|
||||
startBlock = _startBlock;
|
||||
endBlock = _endBlock;
|
||||
rate = _rate;
|
||||
wallet = _wallet;
|
||||
}
|
||||
|
||||
// creates the token to be sold.
|
||||
// override this method to have crowdsale of a specific mintable token.
|
||||
function createTokenContract() internal returns (MintableToken) {
|
||||
return new MintableToken();
|
||||
}
|
||||
|
||||
|
||||
// fallback function can be used to buy tokens
|
||||
function () payable {
|
||||
buyTokens(msg.sender);
|
||||
}
|
||||
|
||||
// low level token purchase function
|
||||
function buyTokens(address beneficiary) payable {
|
||||
require(beneficiary != 0x0);
|
||||
require(validPurchase());
|
||||
|
||||
uint256 weiAmount = msg.value;
|
||||
uint256 updatedWeiRaised = weiRaised.add(weiAmount);
|
||||
|
||||
// calculate token amount to be created
|
||||
uint256 tokens = weiAmount.mul(rate);
|
||||
|
||||
// update state
|
||||
weiRaised = updatedWeiRaised;
|
||||
|
||||
token.mint(beneficiary, tokens);
|
||||
TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
|
||||
|
||||
forwardFunds();
|
||||
}
|
||||
|
||||
// send ether to the fund collection wallet
|
||||
// override to create custom fund forwarding mechanisms
|
||||
function forwardFunds() internal {
|
||||
wallet.transfer(msg.value);
|
||||
}
|
||||
|
||||
// @return true if the transaction can buy tokens
|
||||
function validPurchase() internal constant returns (bool) {
|
||||
uint256 current = block.number;
|
||||
bool withinPeriod = current >= startBlock && current <= endBlock;
|
||||
bool nonZeroPurchase = msg.value != 0;
|
||||
return withinPeriod && nonZeroPurchase;
|
||||
}
|
||||
|
||||
// @return true if crowdsale event has ended
|
||||
function hasEnded() public constant returns (bool) {
|
||||
return block.number > endBlock;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
39
contracts/crowdsale/FinalizableCrowdsale.sol
Normal file
39
contracts/crowdsale/FinalizableCrowdsale.sol
Normal file
@ -0,0 +1,39 @@
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import '../SafeMath.sol';
|
||||
import '../ownership/Ownable.sol';
|
||||
import './Crowdsale.sol';
|
||||
|
||||
/**
|
||||
* @title FinalizableCrowdsale
|
||||
* @dev Extension of Crowsdale where an owner can do extra work
|
||||
* after finishing. By default, it will end token minting.
|
||||
*/
|
||||
contract FinalizableCrowdsale is Crowdsale, Ownable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
bool public isFinalized = false;
|
||||
|
||||
event Finalized();
|
||||
|
||||
// should be called after crowdsale ends, to do
|
||||
// some extra finalization work
|
||||
function finalize() onlyOwner {
|
||||
require(!isFinalized);
|
||||
require(hasEnded());
|
||||
|
||||
finalization();
|
||||
Finalized();
|
||||
|
||||
isFinalized = true;
|
||||
}
|
||||
|
||||
// end token minting on finalization
|
||||
// override this with custom logic if needed
|
||||
function finalization() internal {
|
||||
token.finishMinting();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
56
contracts/crowdsale/RefundVault.sol
Normal file
56
contracts/crowdsale/RefundVault.sol
Normal file
@ -0,0 +1,56 @@
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import '../SafeMath.sol';
|
||||
import '../ownership/Ownable.sol';
|
||||
|
||||
/**
|
||||
* @title RefundVault
|
||||
* @dev This contract is used for storing funds while a crowdsale
|
||||
* is in progress. Supports refunding the money if crowdsale fails,
|
||||
* and forwarding it if crowdsale is successful.
|
||||
*/
|
||||
contract RefundVault is Ownable {
|
||||
using SafeMath for uint256;
|
||||
|
||||
enum State { Active, Refunding, Closed }
|
||||
|
||||
mapping (address => uint256) public deposited;
|
||||
address public wallet;
|
||||
State public state;
|
||||
|
||||
event Closed();
|
||||
event RefundsEnabled();
|
||||
event Refunded(address indexed beneficiary, uint256 weiAmount);
|
||||
|
||||
function RefundVault(address _wallet) {
|
||||
require(_wallet != 0x0);
|
||||
wallet = _wallet;
|
||||
state = State.Active;
|
||||
}
|
||||
|
||||
function deposit(address investor) onlyOwner payable {
|
||||
require(state == State.Active);
|
||||
deposited[investor] = deposited[investor].add(msg.value);
|
||||
}
|
||||
|
||||
function close() onlyOwner {
|
||||
require(state == State.Active);
|
||||
state = State.Closed;
|
||||
Closed();
|
||||
wallet.transfer(this.balance);
|
||||
}
|
||||
|
||||
function enableRefunds() onlyOwner {
|
||||
require(state == State.Active);
|
||||
state = State.Refunding;
|
||||
RefundsEnabled();
|
||||
}
|
||||
|
||||
function refund(address investor) {
|
||||
require(state == State.Refunding);
|
||||
uint256 depositedValue = deposited[investor];
|
||||
deposited[investor] = 0;
|
||||
investor.transfer(depositedValue);
|
||||
Refunded(investor, depositedValue);
|
||||
}
|
||||
}
|
||||
59
contracts/crowdsale/RefundableCrowdsale.sol
Normal file
59
contracts/crowdsale/RefundableCrowdsale.sol
Normal file
@ -0,0 +1,59 @@
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import '../SafeMath.sol';
|
||||
import './FinalizableCrowdsale.sol';
|
||||
import './RefundVault.sol';
|
||||
|
||||
|
||||
/**
|
||||
* @title RefundableCrowdsale
|
||||
* @dev Extension of Crowdsale contract that adds a funding goal, and
|
||||
* the possibility of users getting a refund if goal is not met.
|
||||
* Uses a RefundVault as the crowdsale's vault.
|
||||
*/
|
||||
contract RefundableCrowdsale is FinalizableCrowdsale {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// minimum amount of funds to be raised in weis
|
||||
uint256 public goal;
|
||||
|
||||
// refund vault used to hold funds while crowdsale is running
|
||||
RefundVault public vault;
|
||||
|
||||
function RefundableCrowdsale(uint256 _goal) {
|
||||
vault = new RefundVault(wallet);
|
||||
goal = _goal;
|
||||
}
|
||||
|
||||
// We're overriding the fund forwarding from Crowdsale.
|
||||
// In addition to sending the funds, we want to call
|
||||
// the RefundVault deposit function
|
||||
function forwardFunds() internal {
|
||||
vault.deposit.value(msg.value)(msg.sender);
|
||||
}
|
||||
|
||||
// if crowdsale is unsuccessful, investors can claim refunds here
|
||||
function claimRefund() {
|
||||
require(isFinalized);
|
||||
require(!goalReached());
|
||||
|
||||
vault.refund(msg.sender);
|
||||
}
|
||||
|
||||
// vault finalization task, called when owner calls finalize()
|
||||
function finalization() internal {
|
||||
if (goalReached()) {
|
||||
vault.close();
|
||||
} else {
|
||||
vault.enableRefunds();
|
||||
}
|
||||
|
||||
super.finalization();
|
||||
}
|
||||
|
||||
function goalReached() public constant returns (bool) {
|
||||
return weiRaised >= goal;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
|
||||
import "./StandardToken.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title CrowdsaleToken
|
||||
*
|
||||
* @dev Simple ERC20 Token example, with crowdsale token creation
|
||||
* @dev IMPORTANT NOTE: do not use or deploy this contract as-is. It needs some changes to be
|
||||
* production ready.
|
||||
*/
|
||||
contract CrowdsaleToken is StandardToken {
|
||||
|
||||
string public constant name = "CrowdsaleToken";
|
||||
string public constant symbol = "CRW";
|
||||
uint256 public constant decimals = 18;
|
||||
// replace with your fund collection multisig address
|
||||
address public constant multisig = 0x0;
|
||||
|
||||
|
||||
// 1 ether = 500 example tokens
|
||||
uint256 public constant PRICE = 500;
|
||||
|
||||
/**
|
||||
* @dev Fallback function which receives ether and sends the appropriate number of tokens to the
|
||||
* msg.sender.
|
||||
*/
|
||||
function () payable {
|
||||
createTokens(msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates tokens and send to the specified address.
|
||||
* @param recipient The address which will recieve the new tokens.
|
||||
*/
|
||||
function createTokens(address recipient) payable {
|
||||
if (msg.value == 0) {
|
||||
throw;
|
||||
}
|
||||
|
||||
uint256 tokens = msg.value.mul(getPrice());
|
||||
totalSupply = totalSupply.add(tokens);
|
||||
|
||||
balances[recipient] = balances[recipient].add(tokens);
|
||||
|
||||
if (!multisig.send(msg.value)) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev replace this with any other price function
|
||||
* @return The price per unit of token.
|
||||
*/
|
||||
function getPrice() constant returns (uint256 result) {
|
||||
return PRICE;
|
||||
}
|
||||
}
|
||||
@ -7,19 +7,15 @@ import '../lifecycle/Pausable.sol';
|
||||
* Pausable token
|
||||
*
|
||||
* Simple ERC20 Token example, with pausable token creation
|
||||
* Issue:
|
||||
* https://github.com/OpenZeppelin/zeppelin-solidity/issues/194
|
||||
* Based on code by BCAPtoken:
|
||||
* https://github.com/BCAPtoken/BCAPToken/blob/5cb5e76338cc47343ba9268663a915337c8b268e/sol/BCAPToken.sol#L27
|
||||
**/
|
||||
|
||||
contract PausableToken is StandardToken, Pausable {
|
||||
|
||||
function transfer(address _to, uint256 _value) whenNotPaused {
|
||||
function transfer(address _to, uint _value) whenNotPaused {
|
||||
super.transfer(_to, _value);
|
||||
}
|
||||
|
||||
function transferFrom(address _from, address _to, uint256 _value) whenNotPaused {
|
||||
function transferFrom(address _from, address _to, uint _value) whenNotPaused {
|
||||
super.transferFrom(_from, _to, _value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user