Skip to content

Instantly share code, notes, and snippets.

@Ramarti
Created March 2, 2018 18:11
Show Gist options
  • Save Ramarti/bb66f4908a4cf5b24d21ca8480953dcc to your computer and use it in GitHub Desktop.
Save Ramarti/bb66f4908a4cf5b24d21ca8480953dcc to your computer and use it in GitHub Desktop.
Com
pragma solidity ^0.4.18;
import '../math/SafeMath.sol';
import './TokenDistributionStrategy.sol';
/**
* @title CompositeCrowdsale
* @dev CompositeCrowdsale is a base contract for managing a token crowdsale.
* Contrary to a classic crowdsale, it favours composition over inheritance.
*
* Crowdsale behaviour can be modified by specifying TokenDistributionStrategy
* which is a dedicated smart contract that delegates all of the logic managing
* token distribution.
*
* CompositeCrowdsale is at the WIP stage and is meant to illustrate composition
* approach for managing crowdsale logic. It shouldn't be used in production code
* before necessary upgrades and testing.
*/
contract CompositeCrowdsale {
using SafeMath for uint256;
// The token being sold
TokenDistributionStrategy public tokenDistribution;
// start and end timestamps where investments are allowed (both inclusive)
uint256 public startTime;
uint256 public endTime;
// address where funds are collected
address public wallet;
// 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 CompositeCrowdsale(uint256 _startTime, uint256 _endTime, address _wallet, TokenDistributionStrategy _tokenDistribution) public {
require(_startTime >= now);
require(_endTime >= _startTime);
require(_wallet != 0x0);
startTime = _startTime;
endTime = _endTime;
tokenDistribution = _tokenDistribution;
tokenDistribution.initializeDistribution(this);
wallet = _wallet;
}
// fallback function can be used to buy tokens
function () payable public {
buyTokens(msg.sender);
}
// low level token purchase function
function buyTokens(address beneficiary) payable public {
require(beneficiary != 0x0);
require(validPurchase());
require(tokenDistribution.isContributorAccepted(beneficiary));
uint256 weiAmount = msg.value;
// calculate token amount to be created
uint256 tokens = tokenDistribution.calculateTokenAmount(weiAmount, beneficiary);
// update state
weiRaised = weiRaised.add(weiAmount);
tokenDistribution.distributeTokens(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 view returns (bool) {
bool withinPeriod = now >= startTime && now <= endTime;
bool nonZeroPurchase = msg.value != 0;
return withinPeriod && nonZeroPurchase;
}
// @return true if crowdsale event has ended
function hasEnded() view public returns (bool) {
return now > endTime;
}
}
pragma solidity ^0.4.18;
import './TokenDistributionStrategy.sol';
import '../token/ERC20/ERC20.sol';
import '../math/SafeMath.sol';
/**
* @title FixedRateTokenDistributionStrategy
* @dev Strategy that distributes a fixed number of tokens among the contributors.
* It's done in two steps. First, it registers all of the contributions while the sale is active.
* After the crowdsale has ended the contract compensate buyers proportionally to their contributions.
*/
contract FixedPoolTokenDistributionStrategy is TokenDistributionStrategy {
// The token being sold
ERC20 token;
mapping(address => uint256) contributions;
uint256 totalContributed;
function FixedPoolTokenDistributionStrategy(ERC20 _token, uint256 _rate)
TokenDistributionStrategy(_rate) public{
token = _token;
}
/**
* @title distributeTokens
* @dev extensive method to be used in token purchasing, distribute tokens for user according the
* conditions(discounts, bonus, etc)
*/
function distributeTokens(address _beneficiary, uint256 _amount) public onlyCrowdsale {
contributions[_beneficiary] = contributions[_beneficiary].add(_amount);
totalContributed = totalContributed.add(_amount);
}
/**
* @title compensate
* @dev send token to user
*/
function compensate(address _beneficiary) public {
require(crowdsale.hasEnded());
uint256 amount = contributions[_beneficiary].mul(token.totalSupply()).div(totalContributed);
if (token.transfer(_beneficiary, amount)) {
contributions[_beneficiary] = 0;
}
}
/**
* @title getToken
* @dev get selling token instance
*/
function getToken() view public returns(ERC20) {
return token;
}
/**
* @title calculateTokenAmount
* @dev extensive method to be used to calculate token amount acordding to user eth purchase
* calcualte token amount according to the discount period at that moment
*/
function calculateTokenAmount(uint256 weiAmount, address beneficiary) view public returns (uint256 amount) {
return weiAmount.mul(rate);
}
}
pragma solidity ^0.4.18;
import '../token/ERC20/ERC20.sol';
import './CompositeCrowdsale.sol';
import '../math/SafeMath.sol';
/**
* @title TokenDistributionStrategy
* @dev Base abstract contract defining methods that control token distribution
*/
contract TokenDistributionStrategy {
using SafeMath for uint256;
CompositeCrowdsale crowdsale;
uint256 rate;
modifier onlyCrowdsale() {
require(msg.sender == address(crowdsale));
_;
}
function TokenDistributionStrategy(uint256 _rate) public {
require(_rate > 0);
rate = _rate;
}
/**
* @title initializeDistribution
* @dev initialize tokenDistribution by setting crowdsale contract address
*/
function initializeDistribution(CompositeCrowdsale _crowdsale) public {
require(crowdsale == address(0));
require(_crowdsale != address(0));
crowdsale = _crowdsale;
}
/**
* @title isContributorAccepted
* @dev extensive method to be used before purchasing, for example whitelisted crowdsale
*/
function isContributorAccepted(address beneficiary) view public returns (bool accepted){
return true;
}
/**
* @title distributeTokens
* @dev extensive method to be used in token purchasing, distribute tokens for user according the
* conditions(discounts, bonus, etc)
*/
function distributeTokens(address beneficiary, uint amount) public onlyCrowdsale {}
/**
* @title calculateTokenAmount
* @dev extensive method to be used to calculate token amount acordding to user eth purchase
*/
function calculateTokenAmount(uint256 weiAmount, address beneficiary) view public returns (uint256 amount);
/**
* @title getToken
* @dev get selling token instance
*/
function getToken() view public returns(ERC20);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment