commit
5d79d2a9bd
|
@ -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.
|
||||
|
|
|
@ -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 Sá <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);
|
||||
}
|
||||
}
|
|
@ -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 Sá <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 Sá <goncalo.sa@consensys.net>
|
||||
/// @author Gonçalo Sá <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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.8;
|
||||
pragma solidity ^0.4.11;
|
||||
import "./Factory.sol";
|
||||
import "./CodeBugBounty.sol";
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue