diff --git a/SampleCampaign-TokenController.sol b/SampleCampaign-TokenController.sol new file mode 100644 index 0000000..c583ef6 --- /dev/null +++ b/SampleCampaign-TokenController.sol @@ -0,0 +1,194 @@ +pragma solidity ^0.4.6; + +/* + Copyright 2017, Jordi Baylina + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/// @title MilestoneTracker Contract +/// @author Jordi Baylina +/// @dev This contract controls the issuance of tokens for the MiniMe Token +/// Contract. This version specifically acts as a Campaign manager for raising +/// funds for non-profit causes, but it can be customized for any variety of +/// purposes. + +import "MiniMeToken.sol"; + + +/// @dev `Owned` is a base level contract that assigns an `owner` that can be +/// later changed +contract Owned { + /// @dev `owner` is the only address that can call a function with this + /// modifier + modifier onlyOwner { if (msg.sender != owner) throw; _; } + + address public owner; + + /// @notice The Constructor assigns the message sender to be `owner` + function Owned() { owner = msg.sender;} + + /// @notice `owner` can step down and assign some other address to this role + /// @param _newOwner The address of the new owner. 0x0 can be used to create + /// an unowned neutral vault, however that cannot be undone + function changeOwner(address _newOwner) onlyOwner { + owner = _newOwner; + } +} + + +/// @dev This is designed to control the issuance of a MiniMe Token for a +/// non-profit Campaign. This contract effectively dictates the terms of the +/// funding round. + +contract Campaign is TokenController, Owned { + + uint public startFundingTime; // In UNIX Time Format + uint public endFundingTime; // In UNIX Time Format + uint public maximumFunding; // In wei + uint public totalCollected; // In wei + MiniMeToken public tokenContract; // The new token for this Campaign + address public vaultAddress; // The address to hold the funds donated + +/// @notice 'Campaign()' initiates the Campaign by setting its funding +/// parameters +/// @dev There are several checks to make sure the parameters are acceptable +/// @param _startFundingTime The UNIX time that the Campaign will be able to +/// start receiving funds +/// @param _endFundingTime The UNIX time that the Campaign will stop being able +/// to receive funds +/// @param _maximumFunding In wei, the Maximum amount that the Campaign can +/// receive (currently the max is set at 10,000 ETH for the beta) +/// @param _vaultAddress The address that will store the donated funds +/// @param _tokenAddress Address of the token contract this contract controls + + function Campaign( + uint _startFundingTime, + uint _endFundingTime, + uint _maximumFunding, + address _vaultAddress, + address _tokenAddress + ) { + if ((_endFundingTime < now) || // Cannot end in the past + (_endFundingTime <= _startFundingTime) || + (_maximumFunding > 10000 ether) || // The Beta is limited + (_vaultAddress == 0)) // To prevent burning ETH + { + throw; + } + startFundingTime = _startFundingTime; + endFundingTime = _endFundingTime; + maximumFunding = _maximumFunding; + tokenContract = MiniMeToken(_tokenAddress);// The Deployed Token Contract + vaultAddress = _vaultAddress; + } + +/// @dev The fallback function is called when ether is sent to the contract, it +/// simply calls `doPayment()` with the address that sent the ether as the +/// `_owner`. Payable is a required solidity modifier for functions to receive +/// ether, without this modifier functions will throw if ether is sent to them + + function () payable { + doPayment(msg.sender); + } + +///////////////// +// TokenController interface +///////////////// + +/// @notice `proxyPayment()` allows the caller to send ether to the Campaign and +/// have the tokens created in an address of their choosing +/// @param _owner The address that will hold the newly created tokens + + function proxyPayment(address _owner) payable returns(bool) { + doPayment(_owner); + return true; + } + +/// @notice Notifies the controller about a transfer, for this Campaign all +/// transfers are allowed by default and no extra notifications are needed +/// @param _from The origin of the transfer +/// @param _to The destination of the transfer +/// @param _amount The amount of the transfer +/// @return False if the controller does not authorize the transfer + function onTransfer(address _from, address _to, uint _amount) returns(bool) { + return true; + } + +/// @notice Notifies the controller about an approval, for this Campaign all +/// approvals are allowed by default and no extra notifications are needed +/// @param _owner The address that calls `approve()` +/// @param _spender The spender in the `approve()` call +/// @param _amount The amount in the `approve()` call +/// @return False if the controller does not authorize the approval + function onApprove(address _owner, address _spender, uint _amount) + returns(bool) + { + return true; + } + + +/// @dev `doPayment()` is an internal function that sends the ether that this +/// contract receives to the `vault` and creates tokens in the address of the +/// `_owner` assuming the Campaign is still accepting funds +/// @param _owner The address that will hold the newly created tokens + + function doPayment(address _owner) internal { + +// First check that the Campaign is allowed to receive this donation + if ((nowendFundingTime) || + (tokenContract.controller() == 0) || // Extra check + (msg.value == 0) || + (totalCollected + msg.value > maximumFunding)) + { + throw; + } + +//Track how much the Campaign has collected + totalCollected += msg.value; + +//Send the ether to the vault + if (!vaultAddress.send(msg.value)) { + throw; + } + +// Creates an equal amount of tokens as ether sent. The new tokens are created +// in the `_owner` address + if (!tokenContract.generateTokens(_owner, msg.value)) { + throw; + } + + return; + } + +/// @notice `finalizeFunding()` ends the Campaign by calling setting the +/// controller to 0, thereby ending the issuance of new tokens and stopping the +/// Campaign from receiving more ether +/// @dev `finalizeFunding()` can only be called after the end of the funding period. + + function finalizeFunding() { + if (now < endFundingTime) throw; + tokenContract.changeController(0); + } + + +/// @notice `onlyOwner` changes the location that ether is sent +/// @param _newVaultAddress The address that will receive the ether sent to this +/// Campaign + function setVault(address _newVaultAddress) onlyOwner { + vaultAddress = _newVaultAddress; + } + +}