Created
June 9, 2020 17:59
-
-
Save igastatus/e42ab735d4867e1670d44aa65a4d902f 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=soljson-v0.5.4+commit.9549d8ff.js&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
// We will be using Solidity version 0.5.4 | |
pragma solidity 0.5.4; | |
// Importing OpenZeppelin's SafeMath Implementation | |
import 'https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/1fd993bc01890bf6bd974aaf3d709bdf0a79b9bf/contracts/math/SafeMath.sol'; | |
contract Crowdfunding { | |
using SafeMath for uint256; | |
// List of existing projects | |
Project[] private projects; | |
// Event that will be emitted whenever a new project is started | |
event ProjectStarted( | |
address contractAddress, | |
address projectStarter, | |
string projectTitle, | |
string projectDesc, | |
uint256 deadline, | |
uint256 goalAmount | |
); | |
/** @dev Function to start a new project. | |
* @param title Title of the project to be created | |
* @param description Brief description about the project | |
* @param durationInDays Project deadline in days | |
* @param amountToRaise Project goal in wei | |
*/ | |
function startProject( | |
string calldata title, | |
string calldata description, | |
uint durationInDays, | |
uint amountToRaise | |
) external { | |
uint raiseUntil = now.add(durationInDays.mul(1 days)); | |
Project newProject = new Project(msg.sender, title, description, raiseUntil, amountToRaise); | |
projects.push(newProject); | |
emit ProjectStarted( | |
address(newProject), | |
msg.sender, | |
title, | |
description, | |
raiseUntil, | |
amountToRaise | |
); | |
} | |
/** @dev Function to get all projects' contract addresses. | |
* @return A list of all projects' contract addreses | |
*/ | |
function returnAllProjects() external view returns(Project[] memory){ | |
return projects; | |
} | |
} | |
contract Project { | |
using SafeMath for uint256; | |
// Data structures | |
enum State { | |
Fundraising, | |
Expired, | |
Successful | |
} | |
// State variables | |
address payable public creator; | |
uint public amountGoal; // required to reach at least this much, else everyone gets refund | |
uint public completeAt; | |
uint256 public currentBalance; | |
uint public raiseBy; | |
string public title; | |
string public description; | |
State public state = State.Fundraising; // initialize on create | |
mapping (address => uint) public contributions; | |
// Event that will be emitted whenever funding will be received | |
event FundingReceived(address contributor, uint amount, uint currentTotal); | |
// Event that will be emitted whenever the project starter has received the funds | |
event CreatorPaid(address recipient); | |
// Modifier to check current state | |
modifier inState(State _state) { | |
require(state == _state); | |
_; | |
} | |
// Modifier to check if the function caller is the project creator | |
modifier isCreator() { | |
require(msg.sender == creator); | |
_; | |
} | |
constructor | |
( | |
address payable projectStarter, | |
string memory projectTitle, | |
string memory projectDesc, | |
uint fundRaisingDeadline, | |
uint goalAmount | |
) public { | |
creator = projectStarter; | |
title = projectTitle; | |
description = projectDesc; | |
amountGoal = goalAmount; | |
raiseBy = fundRaisingDeadline; | |
currentBalance = 0; | |
} | |
/** @dev Function to fund a certain project. | |
*/ | |
function contribute() external inState(State.Fundraising) payable { | |
require(msg.sender != creator); | |
contributions[msg.sender] = contributions[msg.sender].add(msg.value); | |
currentBalance = currentBalance.add(msg.value); | |
emit FundingReceived(msg.sender, msg.value, currentBalance); | |
checkIfFundingCompleteOrExpired(); | |
} | |
/** @dev Function to change the project state depending on conditions. | |
*/ | |
function checkIfFundingCompleteOrExpired() public { | |
if (currentBalance >= amountGoal) { | |
state = State.Successful; | |
payOut(); | |
} else if (now > raiseBy) { | |
state = State.Expired; | |
} | |
completeAt = now; | |
} | |
/** @dev Function to give the received funds to project starter. | |
*/ | |
function payOut() internal inState(State.Successful) returns (bool) { | |
uint256 totalRaised = currentBalance; | |
currentBalance = 0; | |
if (creator.send(totalRaised)) { | |
emit CreatorPaid(creator); | |
return true; | |
} else { | |
currentBalance = totalRaised; | |
state = State.Successful; | |
} | |
return false; | |
} | |
/** @dev Function to retrieve donated amount when a project expires. | |
*/ | |
function getRefund() public inState(State.Expired) returns (bool) { | |
require(contributions[msg.sender] > 0); | |
uint amountToRefund = contributions[msg.sender]; | |
contributions[msg.sender] = 0; | |
if (!msg.sender.send(amountToRefund)) { | |
contributions[msg.sender] = amountToRefund; | |
return false; | |
} else { | |
currentBalance = currentBalance.sub(amountToRefund); | |
} | |
return true; | |
} | |
/** @dev Function to get specific information about the project. | |
* @return Returns all the project's details | |
*/ | |
function getDetails() public view returns | |
( | |
address payable projectStarter, | |
string memory projectTitle, | |
string memory projectDesc, | |
uint256 deadline, | |
State currentState, | |
uint256 currentAmount, | |
uint256 goalAmount | |
) { | |
projectStarter = creator; | |
projectTitle = title; | |
projectDesc = description; | |
deadline = raiseBy; | |
currentState = state; | |
currentAmount = currentBalance; | |
goalAmount = amountGoal; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment