major rehaul for COP, state-machine better defined transitions and some minor fixes
This commit is contained in:
parent
0fea8cf9df
commit
d31bc9a442
|
@ -10,7 +10,7 @@ contract StandardBounty {
|
||||||
* Events
|
* Events
|
||||||
*/
|
*/
|
||||||
|
|
||||||
event BountyActivated(address indexed issuer);
|
event BountyActivated(address issuer);
|
||||||
event BountyFulfilled(address indexed fulfiller);
|
event BountyFulfilled(address indexed fulfiller);
|
||||||
event FulfillmentAccepted(address indexed fulfiller, uint256 fulfillmentAmount);
|
event FulfillmentAccepted(address indexed fulfiller, uint256 fulfillmentAmount);
|
||||||
event BountyReclaimed();
|
event BountyReclaimed();
|
||||||
|
@ -34,14 +34,13 @@ contract StandardBounty {
|
||||||
Fulfillment[] public fulfillments; // the list of submitted fulfillments
|
Fulfillment[] public fulfillments; // the list of submitted fulfillments
|
||||||
uint public numFulfillments; // the number of submitted fulfillments
|
uint public numFulfillments; // the number of submitted fulfillments
|
||||||
|
|
||||||
Fulfillment[] public accepted; // the list of accepted fulfillments
|
uint[] public acceptedFulfillmentIndexes; // the list of accepted fulfillments
|
||||||
uint public numAccepted; // the number of accepted fulfillments
|
uint public numAccepted; // the number of accepted fulfillments
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enums
|
* Enums
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// The stage of the bounty
|
|
||||||
enum BountyStages {
|
enum BountyStages {
|
||||||
Draft,
|
Draft,
|
||||||
Active,
|
Active,
|
||||||
|
@ -54,11 +53,83 @@ contract StandardBounty {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct Fulfillment {
|
struct Fulfillment {
|
||||||
|
bool accepted;
|
||||||
address fulfiller;
|
address fulfiller;
|
||||||
string data;
|
string data;
|
||||||
string dataType;
|
string dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modifiers
|
||||||
|
*/
|
||||||
|
|
||||||
|
modifier onlyIssuer() {
|
||||||
|
if (msg.sender != issuer)
|
||||||
|
throw;
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier onlyFulfiller(uint fulNum) {
|
||||||
|
if (msg.sender != fulfillments[fulNum].fulfiller)
|
||||||
|
throw;
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier isBeforeDeadline() {
|
||||||
|
if (now > deadline)
|
||||||
|
throw;
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier newDeadlineIsValid(uint newDeadline) {
|
||||||
|
if (newDeadline <= deadline)
|
||||||
|
throw;
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier isAtStage(BountyStages desiredStage) {
|
||||||
|
if (bountyStage != desiredStage)
|
||||||
|
throw;
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier validateFulfillmentArrayIndex(uint index) {
|
||||||
|
if (index >= numFulfillments)
|
||||||
|
throw;
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier approvalIsNotAutomatic() {
|
||||||
|
if (fulfillmentApproval)
|
||||||
|
throw;
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier validateFunding() {
|
||||||
|
// Less than the minimum contribution is not allowed
|
||||||
|
if (msg.value < fulfillmentAmount)
|
||||||
|
throw;
|
||||||
|
|
||||||
|
// If automatic approval is TRUE then it makes no sense
|
||||||
|
// to have more than one `fulfillmentAmount` to withdraw
|
||||||
|
// given they could withdraw it all by repeatedly sending
|
||||||
|
// the same fulfillment
|
||||||
|
if(fulfillmentApproval && msg.value > fulfillmentAmount) {
|
||||||
|
if (!msg.sender.send(msg.value - fulfillmentAmount))
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If automatic approval is FALSE then issuer may want
|
||||||
|
// to pay multiple and different fulfillments at his discretion
|
||||||
|
// however only makes sense to accept multiples of `fulfillmentAmount`
|
||||||
|
if(!fulfillmentApproval && msg.value % fulfillmentAmount > 0) {
|
||||||
|
if (!msg.sender.send(msg.value - (msg.value % fulfillmentAmount)))
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public functions
|
* Public functions
|
||||||
*/
|
*/
|
||||||
|
@ -74,27 +145,15 @@ contract StandardBounty {
|
||||||
uint _deadline,
|
uint _deadline,
|
||||||
string _data,
|
string _data,
|
||||||
uint _fulfillmentAmount,
|
uint _fulfillmentAmount,
|
||||||
bool _fulfillmentApproval,
|
bool _fulfillmentApproval
|
||||||
bool _activateNow
|
) {
|
||||||
)
|
|
||||||
payable
|
|
||||||
{
|
|
||||||
if (_deadline <= this.timestamp)
|
|
||||||
throw;
|
|
||||||
|
|
||||||
issuer = msg.sender;
|
issuer = msg.sender;
|
||||||
bountyStage = BountyStages.Draft; //automatically in draft stage
|
bountyStage = BountyStages.Draft;
|
||||||
|
|
||||||
deadline = _deadline;
|
deadline = _deadline;
|
||||||
data = _data;
|
data = _data;
|
||||||
|
|
||||||
fulfillmentApproval = _fulfillmentApproval;
|
fulfillmentApproval = _fulfillmentApproval;
|
||||||
fulfillmentAmount = _fulfillmentAmount;
|
fulfillmentAmount = _fulfillmentAmount;
|
||||||
|
|
||||||
if (msg.value >= _fulfillmentAmount && _activateNow) {
|
|
||||||
bountyStage = BountyStages.Active; // Sender supplied bounty with sufficient funds
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Send funds to activate the bug bounty
|
/// @notice Send funds to activate the bug bounty
|
||||||
|
@ -103,12 +162,11 @@ contract StandardBounty {
|
||||||
function addFundsToActivateBounty()
|
function addFundsToActivateBounty()
|
||||||
payable
|
payable
|
||||||
public
|
public
|
||||||
|
isBeforeDeadline
|
||||||
|
onlyIssuer
|
||||||
|
validateFunding
|
||||||
{
|
{
|
||||||
if (block.timestamp >= deadline)
|
transitionToState(BountyStages.Active);
|
||||||
throw;
|
|
||||||
if (this.balance >= fulfillmentAmount && msg.sender == issuer) {
|
|
||||||
bountyStage = BountyStages.Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
BountyActivated(msg.sender);
|
BountyActivated(msg.sender);
|
||||||
}
|
}
|
||||||
|
@ -119,21 +177,11 @@ contract StandardBounty {
|
||||||
/// @param _dataType a meaningful description of the type of data the fulfillment represents
|
/// @param _dataType a meaningful description of the type of data the fulfillment represents
|
||||||
function fulfillBounty(string _data, string _dataType)
|
function fulfillBounty(string _data, string _dataType)
|
||||||
public
|
public
|
||||||
|
isBeforeDeadline
|
||||||
{
|
{
|
||||||
if (msg.sender != issuer || block.timestamp > deadline)
|
fulfillments[numFulfillments] = Fulfillment(fulfillmentApproval, msg.sender, _data, _dataType);
|
||||||
throw;
|
|
||||||
|
|
||||||
fulfillments[numFulfillments] = Fulfillment(msg.sender, _data, _dataType);
|
|
||||||
numFulfillments ++;
|
numFulfillments ++;
|
||||||
|
|
||||||
if (!fulfillmentApproval) { //fulfillment doesn't need to be approved to pay out
|
|
||||||
if (!msg.sender.send(fulfillmentAmount))
|
|
||||||
throw;
|
|
||||||
if (this.balance < fulfillmentAmount) {
|
|
||||||
bountyStage = BountyStages.Fulfilled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BountyFulfilled(msg.sender);
|
BountyFulfilled(msg.sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,25 +190,34 @@ contract StandardBounty {
|
||||||
/// @param fulNum the index of the fulfillment being accepted
|
/// @param fulNum the index of the fulfillment being accepted
|
||||||
function acceptFulfillment(uint fulNum)
|
function acceptFulfillment(uint fulNum)
|
||||||
public
|
public
|
||||||
|
approvalIsNotAutomatic
|
||||||
|
onlyIssuer
|
||||||
|
isAtStage(BountyStages.Active)
|
||||||
|
validateFulfillmentArrayIndex(fulNum)
|
||||||
{
|
{
|
||||||
if (msg.sender != issuer)
|
fulfillments[fulNum].accepted = true;
|
||||||
throw;
|
accepted[numAccepted] = fulNum;
|
||||||
if (bountyStage != BountyStages.Active)
|
numAccepted ++;
|
||||||
throw;
|
|
||||||
if (fulNum >= numFulfillments)
|
|
||||||
throw;
|
|
||||||
|
|
||||||
|
FulfillmentAccepted(msg.sender, fulfillmentAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev acceptFulfillment(): accept a given fulfillment, and send
|
||||||
|
/// the fulfiller their owed funds
|
||||||
|
/// @param fulNum the index of the fulfillment being accepted
|
||||||
|
function fulfillmentPayment(uint fulNum)
|
||||||
|
public
|
||||||
|
isAtStage(BountyStages.Active)
|
||||||
|
validateFulfillmentArrayIndex(fulNum)
|
||||||
|
onlyFulfiller(fulNum)
|
||||||
|
{
|
||||||
accepted[numAccepted] = fulfillments[fulNum];
|
accepted[numAccepted] = fulfillments[fulNum];
|
||||||
numAccepted ++;
|
numAccepted ++;
|
||||||
|
|
||||||
if (!fulfillments[fulNum].fulfiller.send(fulfillmentAmount))
|
if (!fulfillments[fulNum].fulfiller.send(fulfillmentAmount))
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
if (this.balance < fulfillmentAmount) {
|
transitionToState(BountyStages.Fulfilled);
|
||||||
bountyStage = BountyStages.Fulfilled;
|
|
||||||
if (!issuer.send(this.balance))
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
FulfillmentAccepted(msg.sender, fulfillmentAmount);
|
FulfillmentAccepted(msg.sender, fulfillmentAmount);
|
||||||
}
|
}
|
||||||
|
@ -170,10 +227,9 @@ contract StandardBounty {
|
||||||
/// either killed in draft stage, or never accepted any fulfillments
|
/// either killed in draft stage, or never accepted any fulfillments
|
||||||
function reclaimBounty()
|
function reclaimBounty()
|
||||||
public
|
public
|
||||||
|
onlyIssuer
|
||||||
|
transitionToState(BountyStages.Dead)
|
||||||
{
|
{
|
||||||
if (bountyStage == BountyStages.Draft || bountyStage == BountyStages.Active) {
|
|
||||||
bountyStage = BountyStages.Dead;
|
|
||||||
}
|
|
||||||
if (!issuer.send(this.balance))
|
if (!issuer.send(this.balance))
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
|
@ -182,17 +238,35 @@ contract StandardBounty {
|
||||||
|
|
||||||
/// @dev extendDeadline(): allows the issuer to add more time to the
|
/// @dev extendDeadline(): allows the issuer to add more time to the
|
||||||
/// bounty, allowing it to continue accepting fulfillments
|
/// bounty, allowing it to continue accepting fulfillments
|
||||||
|
/// @param _newDeadline the new deadline in timestamp format
|
||||||
function extendDeadline(uint _newDeadline)
|
function extendDeadline(uint _newDeadline)
|
||||||
public
|
public
|
||||||
|
onlyIssuer
|
||||||
|
newDeadlineIsValid(_newDeadline)
|
||||||
{
|
{
|
||||||
if (msg.sender != issuer)
|
|
||||||
throw;
|
|
||||||
|
|
||||||
if (_newDeadline > deadline) {
|
|
||||||
deadline = _newDeadline;
|
deadline = _newDeadline;
|
||||||
}
|
|
||||||
DeadlineExtended(_newDeadline);
|
DeadlineExtended(_newDeadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @dev transitionToState(): transitions the contract to the
|
||||||
|
/// state passed in the parameter `_newStage`
|
||||||
|
/// @param _newStage the new stage to transition to
|
||||||
|
function transitionToState(BountyStages _newStage)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
if (_newStage == BountyStages.Active)
|
||||||
|
bountyStage = _newStage;
|
||||||
|
else if (_newStage == BountyStages.Dead && (bountyStage == BountyStages.Draft || bountyStage == BountyStages.Active))
|
||||||
|
bountyStage = _newStage;
|
||||||
|
else if (_newStage == BountyStages.Fulfilled && this.balance < fulfillmentAmount) {
|
||||||
|
bountyStage = _newStage;
|
||||||
|
if (!issuer.send(this.balance))
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue