Merge pull request #7 from ConsenSys/develop

Develop
This commit is contained in:
mbeylin 2017-05-23 20:28:20 -04:00 committed by GitHub
commit 5d79d2a9bd
5 changed files with 106 additions and 75 deletions

View File

@ -8,8 +8,6 @@
A set of standard contracts to be used as interfaces for any kind of bounty, either qualitative or quantitative in nature.
Original concept & code by @mbeylin. Maintained by @gnsps & @mbeylin.
## 1. Rationale
Bounties can be used to facilitate transactions between two parties, where a quantitative task, qualitative task or artifact is being exchanged for ETH.

View File

@ -0,0 +1,33 @@
pragma solidity ^0.4.11;
import "./Factory.sol";
import "./StandardBounty.sol";
/// @title Code bug bounties factory, concept by Stefan George - <stefan.george@consensys.net>
/// @author Gonçalo <goncalo.sa@consensys.net>
contract BountyFactory is Factory {
/// @dev Allows multiple creations of bounties
/// @param _deadline the unix timestamp after which fulfillments will no longer be accepted
/// @param _contactInfo a string with contact info of the issuer, for them to be contacted if needed
/// @param _data the requirements of the bounty
/// @param _fulfillmentAmount the amount of wei to be paid out for each successful fulfillment
function create(
uint _deadline,
string _contactInfo,
string _data,
uint _fulfillmentAmount
)
public
returns (address bounty)
{
bounty = new StandardBounty(
_deadline,
_contactInfo,
_data,
_fulfillmentAmount
);
register(bounty);
}
}

View File

@ -1,15 +1,15 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./StandardBounty.sol";
/// @title Bountied
/// @dev Contract to be tested and that should disburse the
/// @dev Contract to be tested and that should disburse the
/// `fulfillmentAmount` if it is sees its invariant truths broken
/// @author Gonçalo <goncalo.sa@consensys.net>
contract Bountied {
/// @dev checkInvariant(): function definition of a function that
/// returns a boolean of constant truths you wish to maintain in
/// returns a boolean of constant truths you wish to maintain in
/// this logical copy of your bountied contract
function checkInvariant() returns(bool);
@ -19,7 +19,7 @@ contract Bountied {
/// @title CodeBugBounty
/// @dev extension of StandardBounty to be used specifically for code bug bounties
/// Concept borrowed
/// @author Gonçalo <goncalo.sa@consensys.net>
/// @author Gonçalo <goncalo.sa@consensys.net>, Mark Beylin <mark.beylin@consensys.net>
contract CodeBugBounty is StandardBounty {
/*
@ -33,9 +33,14 @@ contract CodeBugBounty is StandardBounty {
*/
modifier checkBountiedInvariants(address _bountiedContract) {
if (_bountiedContract.checkInvariant()) {
throw;
}
Bountied newBountiedContract = Bountied(_bountiedContract);
require(newBountiedContract.checkInvariant());
_;
}
modifier checkBountiedInvariantsFailed() {
require(!bountiedContract.checkInvariant());
_;
}
/*
@ -58,8 +63,7 @@ contract CodeBugBounty is StandardBounty {
_deadline,
_data,
_contactInfo,
_fulfillmentAmount,
false
_fulfillmentAmount
)
checkBountiedInvariants(_bountiedContract)
{
@ -73,8 +77,7 @@ contract CodeBugBounty is StandardBounty {
public
isAtStage(BountyStages.Active)
validateFulfillmentArrayIndex(fulNum)
checkBountiedInvariants(bountiedContract)
canTransitionToState(BountyStages.Dead)
checkBountiedInvariantsFailed()
{
fulfillments[fulNum].accepted = true;
accepted[numAccepted] = fulNum;
@ -85,4 +88,4 @@ contract CodeBugBounty is StandardBounty {
FulfillmentAccepted(msg.sender, fulfillmentAmount);
}
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
import "./Factory.sol";
import "./CodeBugBounty.sol";

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.8;
pragma solidity ^0.4.11;
/// @title StandardBounty
@ -16,7 +16,8 @@ contract StandardBounty {
event BountyFulfilled(address indexed fulfiller, uint256 indexed fulNum);
event FulfillmentAccepted(address indexed fulfiller, uint256 indexed fulNum);
event FulfillmentPaid(address indexed fulfiller, uint256 indexed fulNum);
event BountyReclaimed();
event BountyKilled();
event ContributionAdded(address indexed contributor, uint256 value);
event DeadlineExtended(uint newDeadline);
/*
@ -47,7 +48,6 @@ contract StandardBounty {
enum BountyStages {
Draft,
Active,
Fulfilled,
Dead // bounties past deadline with no accepted fulfillments
}
@ -68,56 +68,56 @@ contract StandardBounty {
*/
modifier onlyIssuer() {
if (msg.sender != issuer)
throw;
require(msg.sender == issuer);
_;
}
modifier notIssuer() {
require(msg.sender != issuer);
_;
}
modifier onlyFulfiller(uint fulNum) {
if (msg.sender != fulfillments[fulNum].fulfiller)
throw;
require(msg.sender == fulfillments[fulNum].fulfiller);
_;
}
modifier amountIsNotZero(uint amount) {
if (amount != 0)
throw;
require(amount == 0);
_;
}
modifier amountEqualsValue(uint amount) {
require((amount * 1 ether) != msg.value);
_;
}
modifier isBeforeDeadline() {
if (now > deadline)
throw;
require(now < deadline);
_;
}
modifier newDeadlineIsValid(uint newDeadline) {
if (newDeadline <= deadline)
throw;
require(newDeadline > deadline);
_;
}
modifier isAtStage(BountyStages desiredStage) {
if (bountyStage != desiredStage)
throw;
require(bountyStage == desiredStage);
_;
}
modifier checkFulfillmentsNumber() {
if (numFulfillments > MAX_FULFILLMENTS)
throw;
require(numFulfillments < MAX_FULFILLMENTS);
_;
}
modifier validateFulfillmentArrayIndex(uint index) {
if (index >= numFulfillments)
throw;
require(index < numFulfillments);
_;
}
modifier checkFulfillmentIsApprovedAndUnpaid(uint fulNum) {
if (fulfillments[fulNum].accepted && fulfillments[fulNum].paid)
throw;
require(fulfillments[fulNum].accepted && !fulfillments[fulNum].paid);
_;
}
@ -129,8 +129,7 @@ contract StandardBounty {
// are refunded. After this, new funds may also be added on an ad-hoc
// basis
if ( (msg.value + this.balance) % fulfillmentAmount > 0) {
if (!msg.sender.send((msg.value + this.balance) % fulfillmentAmount))
throw;
msg.sender.transfer((msg.value + this.balance) % fulfillmentAmount);
}
_;
@ -160,7 +159,25 @@ contract StandardBounty {
deadline = _deadline;
data = _data;
fulfillmentAmount = _fulfillmentAmount;
}
/// @dev contribute(): a function allowing anyone to contribute ether to a
/// bounty, as long as it is still before its deadline. Shouldn't
/// keep ether by accident (hence 'value').
/// @notice Please note you funds will be at the mercy of the issuer
/// and can be drained at any moment. Be careful!
/// @param value the amount being contributed in ether to prevent
/// accidental deposits
function contribute (uint value)
payable
isBeforeDeadline
amountIsNotZero(value)
amountEqualsValue(value)
validateFunding
{
ContributionAdded(msg.sender, msg.value);
}
/// @notice Send funds to activate the bug bounty
@ -185,6 +202,7 @@ contract StandardBounty {
isAtStage(BountyStages.Active)
isBeforeDeadline
checkFulfillmentsNumber
notIssuer
{
fulfillments[numFulfillments] = Fulfillment(false, false, msg.sender, _data, _dataType);
@ -203,10 +221,6 @@ contract StandardBounty {
fulfillments[fulNum].accepted = true;
accepted[numAccepted++] = fulNum;
if (lastFulfillment()){
transitionToState(BountyStages.Fulfilled);
}
FulfillmentAccepted(msg.sender, fulNum);
}
@ -219,29 +233,25 @@ contract StandardBounty {
onlyFulfiller(fulNum)
checkFulfillmentIsApprovedAndUnpaid(fulNum)
{
if (!fulfillments[fulNum].fulfiller.send(fulfillmentAmount))
throw;
fulfillments[fulNum].fulfiller.transfer(fulfillmentAmount);
numPaid++;
FulfillmentPaid(msg.sender, fulNum);
}
/// @dev reclaimBounty(): drains the contract of it's remaining
/// @dev killBounty(): drains the contract of it's remaining
/// funds, and moves the bounty into stage 3 (dead) since it was
/// either killed in draft stage, or never accepted any fulfillments
function reclaimBounty()
function killBounty()
public
onlyIssuer
{
uint unpaidAmount = fulfillmentAmount * (numAccepted - numPaid);
if (!issuer.send(this.balance - unpaidAmount))
throw;
issuer.transfer(this.balance - unpaidAmount());
transitionToState(BountyStages.Dead);
BountyReclaimed();
BountyKilled();
}
/// @dev extendDeadline(): allows the issuer to add more time to the
@ -257,22 +267,23 @@ contract StandardBounty {
DeadlineExtended(_newDeadline);
}
/// @dev (): a fallback function, allowing anyone to contribute ether to a
/// bounty, as long as it is still before its deadline.
/// NOTE: THESE FUNDS ARE AT THE MERCY OF THE ISSUER, AND CAN BE
/// DRAINED AT ANY MOMENT BY THEM. REFUNDS CAN ONLY BE PROVIDED TO THE
/// ISSUER
function()
payable
isBeforeDeadline
{
}
/*
* Internal functions
*/
/// @dev unpaidAmount(): calculates the amount which
/// the bounty has yet to pay out
function unpaidAmount()
public
constant
returns (uint unpaidAmount)
{
unpaidAmount = fulfillmentAmount * (numAccepted - numPaid);
}
/// @dev transitionToState(): transitions the contract to the
/// state passed in the parameter `_newStage` given the
/// conditions stated in the body of the function
@ -282,18 +293,4 @@ contract StandardBounty {
{
bountyStage = _newStage;
}
/// @dev lastFulfillment(): determines if the current
/// fulfillment is the last one which can be accepted,
/// based on the remaining balance
function lastFulfillment()
internal
returns (bool isFulfilled)
{
uint unpaidAmount = fulfillmentAmount * (numAccepted - numPaid);
isFulfilled = ((this.balance - unpaidAmount) < fulfillmentAmount);
}
}