Created
June 29, 2018 08:47
-
-
Save zhangsoledad/4dd0fb4e42655579d1627d02682ec3b0 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=undefined&optimize=false&gist=
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.0; | |
import "./Ownable.sol"; | |
import "./SafeMath.sol"; | |
import "./State.sol"; | |
contract Hackathon is Ownable, HackathonState { | |
using SafeMath for uint256; | |
uint256 public initFound; | |
uint256 public totalCrowdFound; | |
uint256 public totalFound; | |
mapping(address => uint256) internal crowdFound; | |
uint256 public crowdFoundTarget; | |
uint256 public crowdFoundPeriod; | |
uint256 public signUpPeriod; | |
uint256 public matchPeriod; | |
uint256 public votePeriod; | |
uint256 public closingCrowdFound; | |
uint256 public closingSignUp; | |
uint256 public closingMatch; | |
uint256 public closingVote; | |
uint256 public deposit; | |
uint256 public signUpFee; | |
uint256 public champBonus; | |
uint256 public secondBonus; | |
uint256 public thirdBonus; | |
uint256 public voteBonus; | |
address [] registers; | |
mapping(address => bool) internal registersMap; | |
mapping(address => bool) internal voted; | |
address [] voters; | |
mapping(address => address) internal voteTargets; | |
mapping(address => uint256) internal votes; | |
uint256 public registerUpperLimit; | |
uint256 public registerLowerLimit; | |
address public champ; | |
address public second; | |
address public third; | |
mapping(address => uint256) internal bonus; | |
address [] voteWiners; | |
function Hackathon( | |
uint256 _crowdFoundTarget, | |
uint256 _crowdFoundPeriod, | |
uint256 _signUpPeriod, | |
uint256 _matchPeriod, | |
uint256 _votePeriod, | |
uint256 _deposit, | |
uint256 _signUpFee, | |
uint256 _champBonus, | |
uint256 _secondBonus, | |
uint256 _thirdBonus, | |
uint256 _voteBonus, | |
uint256 _registerUpperLimit, | |
uint256 _registerLowerLimit | |
) public payable { | |
require(_crowdFoundPeriod > 0); | |
require(_signUpPeriod > 0); | |
require(_matchPeriod > 0); | |
require(_votePeriod > 0); | |
require(_champBonus <= 100); | |
require(_secondBonus <= 100); | |
require(_thirdBonus <= 100); | |
require(_voteBonus <= 100); | |
require(_champBonus.add(_secondBonus).add(_thirdBonus).add(_voteBonus) == 100); | |
require(_registerUpperLimit >= _registerLowerLimit); | |
require(_registerLowerLimit > 0); | |
initFound = msg.value; | |
totalFound = msg.value; | |
crowdFoundTarget = _crowdFoundTarget; | |
crowdFoundPeriod = _crowdFoundPeriod; | |
signUpPeriod = _signUpPeriod; | |
matchPeriod = _matchPeriod; | |
votePeriod = _votePeriod; | |
deposit = _deposit; | |
signUpFee = _signUpFee; | |
champBonus = _champBonus; | |
secondBonus = _secondBonus; | |
thirdBonus = _thirdBonus; | |
voteBonus = _voteBonus; | |
registerUpperLimit = _registerUpperLimit; | |
registerLowerLimit = _registerLowerLimit; | |
} | |
function startCrowdFound() public requireState(State.Created) onlyOwner { | |
state = State.CrowFound; | |
closingCrowdFound = block.timestamp.add(crowdFoundPeriod); | |
} | |
function buy(address _beneficiary) public payable requireState(State.CrowFound) { | |
require(totalCrowdFound.add(msg.value) <= crowdFoundTarget); | |
require(block.timestamp <= closingCrowdFound); | |
totalCrowdFound = totalCrowdFound.add(msg.value); | |
totalFound = totalFound.add(msg.value); | |
crowdFound[_beneficiary] = crowdFound[_beneficiary].add(msg.value); | |
} | |
function crowdFoundGoalReached() public view returns (bool) { | |
return totalCrowdFound >= crowdFoundTarget; | |
} | |
function startSignUp() public requireState(State.CrowFound) onlyOwner { | |
require(block.timestamp > closingCrowdFound); | |
require(totalCrowdFound >= crowdFoundTarget); | |
state = State.SignUp; | |
closingSignUp = block.timestamp.add(signUpPeriod); | |
} | |
function signUp(address _register) public payable requireState(State.SignUp) { | |
require(block.timestamp <= closingSignUp); | |
require(msg.value == deposit.add(signUpFee)); | |
require(registers.length < registerUpperLimit); | |
totalFound = totalFound.add(signUpFee); | |
registers.push(_register); | |
registersMap[_register] = true; | |
} | |
function signUpGoalReached() public view returns (bool) { | |
return registers.length >= registerLowerLimit; | |
} | |
function votable(address _person) internal returns (bool) { | |
if ((crowdFound[_person] > 0 || msg.sender == owner) && (!voted[_person]) ) { | |
voted[_person] = true; | |
return true; | |
} | |
return false; | |
} | |
function is_failed() public view returns (bool) { | |
if (state == State.CrowFound && block.timestamp > closingCrowdFound && totalCrowdFound < crowdFoundTarget){ | |
return true; | |
} | |
if (state == State.SignUp && block.timestamp > closingSignUp && registers.length < registerLowerLimit){ | |
return true; | |
} | |
return false; | |
} | |
function failed() public { | |
require(is_failed()); | |
state = State.Failed; | |
} | |
function startMatch() public requireState(State.SignUp) onlyOwner { | |
require(block.timestamp > closingSignUp); | |
require(registers.length >= registerLowerLimit); | |
state = State.Match; | |
closingMatch = block.timestamp.add(matchPeriod); | |
} | |
function startVote() public requireState(State.Match) onlyOwner { | |
require(block.timestamp > closingMatch); | |
state = State.Vote; | |
closingVote = block.timestamp.add(votePeriod); | |
} | |
function vote(address _target) public requireState(State.Vote) { | |
require(block.timestamp <= closingVote); | |
require(registersMap[_target]); | |
// change voted | |
require(votable(msg.sender)); | |
if (msg.sender == owner) { | |
votes[_target] = votes[_target].add(initFound); | |
} | |
if (crowdFound[msg.sender] > 0) { | |
votes[_target] = votes[_target].add(crowdFound[msg.sender]); | |
} | |
voteTargets[msg.sender] = _target; | |
voters.push(msg.sender); | |
} | |
function finalize() public requireState(State.Vote) { | |
require(block.timestamp > closingVote); | |
state = State.Final; | |
address _champ = registers[0]; | |
address _second = registers[0]; | |
address _third = registers[0]; | |
for (uint i = 0; i < registers.length; i++) { | |
if (votes[registers[i]] > votes[_champ]) { | |
_champ = registers[i]; | |
} | |
if (votes[registers[i]] > votes[_second] && votes[registers[i]] < votes[_champ]) { | |
_second = registers[i]; | |
} | |
if (votes[registers[i]] > votes[_third] && votes[registers[i]] < votes[_second]) { | |
_third = registers[i]; | |
} | |
} | |
champ = _champ; | |
second = _second; | |
third = _third; | |
bonus[champ] = totalFound.mul(champBonus).div(100); | |
bonus[second] = totalFound.mul(secondBonus).div(100); | |
bonus[third] = totalFound.mul(thirdBonus).div(100); | |
uint256 voteBonusFound = totalFound.sub(bonus[champ]).sub(bonus[second]).sub(bonus[third]); | |
for (uint j = 0; j < voters.length; j++) { | |
if (voteTargets[voters[j]] == champ) { | |
voteWiners.push(voters[j]); | |
} | |
} | |
uint num = voteWiners.length; | |
for (uint k = 0; k < voteWiners.length; k++) { | |
bonus[voteWiners[k]] = bonus[voteWiners[k]].add(voteBonusFound.div(num)); | |
voteBonusFound.sub(voteBonusFound.div(num)); | |
} | |
if (voteBonusFound > 0) { | |
bonus[owner] = voteBonusFound; | |
} | |
} | |
// Remember to zero the pending refund before | |
function withdraw() public { | |
require(state == State.Final || state == State.Failed); | |
require(owner == msg.sender || crowdFound[msg.sender] > 0); | |
if (state == State.Failed) { | |
if (owner == msg.sender && initFound > 0) { | |
uint256 owner_amount = initFound; | |
initFound = 0; | |
msg.sender.transfer(owner_amount); | |
} | |
if (crowdFound[msg.sender] > 0) { | |
uint256 amount = crowdFound[msg.sender]; | |
crowdFound[msg.sender] = 0; | |
msg.sender.transfer(amount); | |
} | |
if (registersMap[msg.sender]) { | |
registersMap[msg.sender] = false; | |
msg.sender.transfer(deposit); | |
} | |
} | |
if (state == State.Final) { | |
if (registersMap[msg.sender]) { | |
registersMap[msg.sender] = false; | |
msg.sender.transfer(deposit); | |
} | |
if (bonus[msg.sender] > 0 ) { | |
uint256 bonus_amount = bonus[msg.sender]; | |
bonus[msg.sender] = 0; | |
msg.sender.transfer(bonus_amount); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.0; | |
import "./Ownable.sol"; | |
import "./Hackathon.sol"; | |
contract HackathonFactory is Ownable { | |
address public owner; | |
event HackathonCreated( | |
address indexed _owner, | |
address indexed _contract | |
); | |
function HackathonFactory() public { | |
} | |
function CreateHackathon( | |
uint256 _crowdFoundTarget, | |
uint256 _crowdFoundPeriod, | |
uint256 _signUpPeriod, | |
uint256 _matchPeriod, | |
uint256 _votePeriod, | |
uint256 _deposit, | |
uint256 _signUpFee, | |
uint256 _champBonus, | |
uint256 _secondBonus, | |
uint256 _thirdBonus, | |
uint256 _voteBonus, | |
uint256 _registerUpperLimit, | |
uint256 _registerLowerLimit | |
) public payable { | |
Hackathon hackathon = new Hackathon( | |
_crowdFoundTarget, | |
_crowdFoundPeriod, | |
_signUpPeriod, | |
_matchPeriod, | |
_votePeriod, | |
_deposit, | |
_signUpFee, | |
_champBonus, | |
_secondBonus, | |
_thirdBonus, | |
_voteBonus, | |
_registerUpperLimit, | |
_registerLowerLimit | |
); | |
HackathonCreated(msg.sender, address(hackathon)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.0; | |
/** | |
* @title Ownable | |
* @dev The Ownable contract has an owner address, and provides basic authorization control | |
* functions, this simplifies the implementation of "user permissions". | |
*/ | |
contract Ownable { | |
address public owner; | |
event OwnershipRenounced(address indexed previousOwner); | |
event OwnershipTransferred( | |
address indexed previousOwner, | |
address indexed newOwner | |
); | |
/** | |
* @dev The Ownable constructor sets the original `owner` of the contract to the sender | |
* account. | |
*/ | |
function Ownable() public { | |
owner = msg.sender; | |
} | |
/** | |
* @dev Throws if called by any account other than the owner. | |
*/ | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
/** | |
* @dev Allows the current owner to relinquish control of the contract. | |
* @notice Renouncing to ownership will leave the contract without an owner. | |
* It will not be possible to call the functions with the `onlyOwner` | |
* modifier anymore. | |
*/ | |
function renounceOwnership() public onlyOwner { | |
OwnershipRenounced(owner); | |
owner = address(0); | |
} | |
/** | |
* @dev Allows the current owner to transfer control of the contract to a newOwner. | |
* @param _newOwner The address to transfer ownership to. | |
*/ | |
function transferOwnership(address _newOwner) public onlyOwner { | |
_transferOwnership(_newOwner); | |
} | |
/** | |
* @dev Transfers control of the contract to a newOwner. | |
* @param _newOwner The address to transfer ownership to. | |
*/ | |
function _transferOwnership(address _newOwner) internal { | |
require(_newOwner != address(0)); | |
OwnershipTransferred(owner, _newOwner); | |
owner = _newOwner; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.0; | |
/** | |
* @title SafeMath | |
* @dev Math operations with safety checks that throw on error | |
*/ | |
library SafeMath { | |
/** | |
* @dev Multiplies two numbers, throws on overflow. | |
*/ | |
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { | |
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the | |
// benefit is lost if 'b' is also tested. | |
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 | |
if (a == 0) { | |
return 0; | |
} | |
c = a * b; | |
assert(c / a == b); | |
return c; | |
} | |
/** | |
* @dev Integer division of two numbers, truncating the quotient. | |
*/ | |
function div(uint256 a, uint256 b) internal pure returns (uint256) { | |
// assert(b > 0); // Solidity automatically throws when dividing by 0 | |
// uint256 c = a / b; | |
// assert(a == b * c + a % b); // There is no case in which this doesn't hold | |
return a / b; | |
} | |
/** | |
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). | |
*/ | |
function sub(uint256 a, uint256 b) internal pure returns (uint256) { | |
assert(b <= a); | |
return a - b; | |
} | |
/** | |
* @dev Adds two numbers, throws on overflow. | |
*/ | |
function add(uint256 a, uint256 b) internal pure returns (uint256 c) { | |
c = a + b; | |
assert(c >= a); | |
return c; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.0; | |
contract HackathonState { | |
enum State { Created, CrowFound, SignUp, Match, Vote, Final, Failed } // Enum | |
State state; | |
// Modifiers can receive arguments: | |
modifier requireState(State _state) { | |
require(state == _state); | |
_; | |
} | |
function HackathonState() public { | |
state = State.Created; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment