updated docs to most recent version of the contract

This commit is contained in:
mbeylin 2017-10-30 22:56:09 -04:00
parent 610cbb3df6
commit 451e9ed3fe
1 changed files with 36 additions and 62 deletions

View File

@ -32,6 +32,13 @@ The schema for the bounty data field is:
} }
``` ```
The current set of categories in use is:
```
['Code', 'Bugs', 'Questions', 'Graphic Design', 'Social Media', 'Content Creation', 'Translations', 'Surveys']
```
If you would like to add or amend fields in the data schema presented, please open a github issue and they will be added.
`uint public fulfillmentAmount` `uint public fulfillmentAmount`
The number of units which the bounty pays out for successful completion, either in wei or in token units for the relevant contract. The number of units which the bounty pays out for successful completion, either in wei or in token units for the relevant contract.
@ -47,9 +54,6 @@ Bounties are formed in the `Draft` stage, a period during which the issuer can e
Once the bounty state variables are finalized, and the bounty contract holds sufficient funds to pay out each milestone at least once, it can be transitioned to the `Active` stage by only the issuer. During the active stage, the requirements or payout amount cannot be altered, however the deadline may be extended. Fulfillments can only be submitted in the `Active` stage before the deadline, although they may be accepted by the issuer or arbiter even after the deadline has passed. Once the bounty state variables are finalized, and the bounty contract holds sufficient funds to pay out each milestone at least once, it can be transitioned to the `Active` stage by only the issuer. During the active stage, the requirements or payout amount cannot be altered, however the deadline may be extended. Fulfillments can only be submitted in the `Active` stage before the deadline, although they may be accepted by the issuer or arbiter even after the deadline has passed.
At any point, the issuer can kill the bounty returning all funds to them (less the amount due for already accepted but unpaid submissions), transitioning the bounty into the `Dead` stage. However, this behaviour is highly discouraged and should be avoided at all costs. At any point, the issuer can kill the bounty returning all funds to them (less the amount due for already accepted but unpaid submissions), transitioning the bounty into the `Dead` stage. However, this behaviour is highly discouraged and should be avoided at all costs.
`uint owedAmount`
The number of units of tokens or ETH which are owed to bounty fulfillers whose work has been accepted but is yet unpaid.
`uint balance` `uint balance`
The number of units of tokens or ETH which the bounty has under its control. The balance must always be greater than or equal to the owedAmount for a given bounty. The number of units of tokens or ETH which the bounty has under its control. The balance must always be greater than or equal to the owedAmount for a given bounty.
@ -61,8 +65,6 @@ Work is submitted and a hash is stored on-chain, allowing any deliverable to be
`mapping(uint=>uint) public numAccepted` `mapping(uint=>uint) public numAccepted`
The number of submissions which have been accepted for each bounty The number of submissions which have been accepted for each bounty
`mapping(uint=>uint) public numPaid`
The number of submissions which have paid out to task fulfillers for each bounty. `numPaid[_bountyId]` is always less than or equal to `numAccepted[_bountyId]`.
### External functions ### External functions
@ -94,7 +96,7 @@ function issueBounty(
validateNotTooManyBounties validateNotTooManyBounties
returns (uint) returns (uint)
{ {
bounties.push(Bounty(_issuer, _deadline, _data, _fulfillmentAmount, _arbiter, _paysTokens, BountyStages.Draft, 0, 0)); bounties.push(Bounty(_issuer, _deadline, _data, _fulfillmentAmount, _arbiter, _paysTokens, BountyStages.Draft, 0));
if (_paysTokens){ if (_paysTokens){
tokenContracts[bounties.length - 1] = HumanStandardToken(_tokenContract); tokenContracts[bounties.length - 1] = HumanStandardToken(_tokenContract);
} }
@ -125,6 +127,7 @@ function issueAndActivateBounty(
{ {
require (_value >= _fulfillmentAmount); require (_value >= _fulfillmentAmount);
if (_paysTokens){ if (_paysTokens){
require(msg.value == 0);
tokenContracts[bounties.length] = HumanStandardToken(_tokenContract); tokenContracts[bounties.length] = HumanStandardToken(_tokenContract);
require(tokenContracts[bounties.length].transferFrom(msg.sender, this, _value)); require(tokenContracts[bounties.length].transferFrom(msg.sender, this, _value));
} else { } else {
@ -137,7 +140,6 @@ function issueAndActivateBounty(
_arbiter, _arbiter,
_paysTokens, _paysTokens,
BountyStages.Active, BountyStages.Active,
0,
_value)); _value));
BountyIssued(bounties.length - 1); BountyIssued(bounties.length - 1);
ContributionAdded(bounties.length - 1, msg.sender, _value); ContributionAdded(bounties.length - 1, msg.sender, _value);
@ -152,9 +154,9 @@ This allows a bounty to receive 3rd party contributions from the crowd. This fun
function contribute (uint _bountyId, uint _value) function contribute (uint _bountyId, uint _value)
payable payable
public public
validateBountyArrayIndex(_bountyId)
isBeforeDeadline(_bountyId) isBeforeDeadline(_bountyId)
isNotDead(_bountyId) isNotDead(_bountyId)
validateBountyArrayIndex(_bountyId)
amountIsNotZero(_value) amountIsNotZero(_value)
transferredAmountEqualsValue(_bountyId, _value) transferredAmountEqualsValue(_bountyId, _value)
{ {
@ -170,14 +172,13 @@ If the bounty has sufficient funds to pay out at least once, it can be activated
function activateBounty(uint _bountyId, uint _value) function activateBounty(uint _bountyId, uint _value)
payable payable
public public
validateBountyArrayIndex(_bountyId)
isBeforeDeadline(_bountyId) isBeforeDeadline(_bountyId)
onlyIssuer(_bountyId) onlyIssuer(_bountyId)
validateBountyArrayIndex(_bountyId)
transferredAmountEqualsValue(_bountyId, _value) transferredAmountEqualsValue(_bountyId, _value)
{ {
bounties[_bountyId].balance += _value; bounties[_bountyId].balance += _value;
require (bounties[_bountyId].balance >= require (bounties[_bountyId].balance >= bounties[_bountyId].fulfillmentAmount);
(bounties[_bountyId].fulfillmentAmount + bounties[_bountyId].owedAmount));
transitionToState(_bountyId, BountyStages.Active); transitionToState(_bountyId, BountyStages.Active);
ContributionAdded(_bountyId, msg.sender, _value); ContributionAdded(_bountyId, msg.sender, _value);
@ -197,7 +198,7 @@ function fulfillBounty(uint _bountyId, string _data)
isBeforeDeadline(_bountyId) isBeforeDeadline(_bountyId)
notIssuerOrArbiter(_bountyId) notIssuerOrArbiter(_bountyId)
{ {
fulfillments[_bountyId].push(Fulfillment(false, false, msg.sender, _data)); fulfillments[_bountyId].push(Fulfillment(false, msg.sender, _data));
BountyFulfilled(_bountyId, msg.sender, (fulfillments[_bountyId].length - 1)); BountyFulfilled(_bountyId, msg.sender, (fulfillments[_bountyId].length - 1));
} }
@ -225,41 +226,21 @@ Submissions can be accepted by the issuer while the bounty is active, and the co
function acceptFulfillment(uint _bountyId, uint _fulfillmentId) function acceptFulfillment(uint _bountyId, uint _fulfillmentId)
public public
validateBountyArrayIndex(_bountyId) validateBountyArrayIndex(_bountyId)
validateFulfillmentArrayIndex(_bountyId, _fulfillmentId)
onlyIssuerOrArbiter(_bountyId) onlyIssuerOrArbiter(_bountyId)
isAtStage(_bountyId, BountyStages.Active) isAtStage(_bountyId, BountyStages.Active)
validateFulfillmentArrayIndex(_bountyId, _fulfillmentId)
fulfillmentNotYetAccepted(_bountyId, _fulfillmentId) fulfillmentNotYetAccepted(_bountyId, _fulfillmentId)
enoughFundsToPay(_bountyId) enoughFundsToPay(_bountyId)
{ {
fulfillments[_bountyId][_fulfillmentId].accepted = true; fulfillments[_bountyId][_fulfillmentId].accepted = true;
bounties[_bountyId].owedAmount += bounties[_bountyId].fulfillmentAmount;
numAccepted[_bountyId]++; numAccepted[_bountyId]++;
FulfillmentAccepted(_bountyId, msg.sender, _fulfillmentId);
}
```
#### FulfillmentPayment()
Once an individuals submission has been accepted, they can claim their reward, transferring the ETH or tokens to the successful fulfiller. A payment can only be claimed once for each fulfillment which has been accepted.
```
function fulfillmentPayment(uint _bountyId, uint _fulfillmentId)
public
validateBountyArrayIndex(_bountyId)
validateFulfillmentArrayIndex(_bountyId, _fulfillmentId)
onlyFulfiller(_bountyId, _fulfillmentId)
checkFulfillmentIsApprovedAndUnpaid(_bountyId, _fulfillmentId)
{
fulfillments[_bountyId][_fulfillmentId].paid = true;
numPaid[_bountyId]++;
bounties[_bountyId].owedAmount -= bounties[_bountyId].fulfillmentAmount;
bounties[_bountyId].balance -= bounties[_bountyId].fulfillmentAmount; bounties[_bountyId].balance -= bounties[_bountyId].fulfillmentAmount;
if (bounties[_bountyId].paysTokens){ if (bounties[_bountyId].paysTokens){
tokenContracts[_bountyId].transfer(fulfillments[_bountyId][_fulfillmentId].fulfiller, bounties[_bountyId].fulfillmentAmount); require(tokenContracts[_bountyId].transfer(fulfillments[_bountyId][_fulfillmentId].fulfiller, bounties[_bountyId].fulfillmentAmount));
} else { } else {
fulfillments[_bountyId][_fulfillmentId].fulfiller.transfer(bounties[_bountyId].fulfillmentAmount); fulfillments[_bountyId][_fulfillmentId].fulfiller.transfer(bounties[_bountyId].fulfillmentAmount);
} }
FulfillmentPaid(_bountyId, msg.sender, _fulfillmentId); FulfillmentAccepted(_bountyId, msg.sender, _fulfillmentId);
} }
``` ```
@ -272,15 +253,16 @@ function killBounty(uint _bountyId)
onlyIssuer(_bountyId) onlyIssuer(_bountyId)
{ {
transitionToState(_bountyId, BountyStages.Dead); transitionToState(_bountyId, BountyStages.Dead);
uint difference = bounties[_bountyId].balance - bounties[_bountyId].owedAmount; uint oldBalance = bounties[_bountyId].balance;
bounties[_bountyId].balance = bounties[_bountyId].owedAmount; bounties[_bountyId].balance = 0;
if (oldBalance > 0){
if (bounties[_bountyId].paysTokens){ if (bounties[_bountyId].paysTokens){
tokenContracts[_bountyId].transfer(bounties[_bountyId].issuer, difference); require(tokenContracts[_bountyId].transfer(bounties[_bountyId].issuer, oldBalance));
} else { } else {
bounties[_bountyId].issuer.transfer(difference); bounties[_bountyId].issuer.transfer(oldBalance);
} }
}
BountyKilled(_bountyId); BountyKilled(_bountyId, msg.sender);
} }
``` ```
@ -378,17 +360,19 @@ function changeBountyPaysTokens(uint _bountyId, bool _newPaysTokens, address _ne
onlyIssuer(_bountyId) onlyIssuer(_bountyId)
isAtStage(_bountyId, BountyStages.Draft) isAtStage(_bountyId, BountyStages.Draft)
{ {
HumanStandardToken oldToken = tokenContracts[_bountyId];
bool oldPaysTokens = bounties[_bountyId].paysTokens;
bounties[_bountyId].paysTokens = _newPaysTokens;
tokenContracts[_bountyId] = HumanStandardToken(_newTokenContract);
if (bounties[_bountyId].balance > 0){ if (bounties[_bountyId].balance > 0){
uint oldBalance = bounties[_bountyId].balance; uint oldBalance = bounties[_bountyId].balance;
bounties[_bountyId].balance = 0; bounties[_bountyId].balance = 0;
if (bounties[_bountyId].paysTokens){ if (oldPaysTokens){
require(tokenContracts[_bountyId].transfer(bounties[_bountyId].issuer, oldBalance)); require(oldToken.transfer(bounties[_bountyId].issuer, oldBalance));
} else { } else {
bounties[_bountyId].issuer.transfer(oldBalance); bounties[_bountyId].issuer.transfer(oldBalance);
} }
} }
bounties[_bountyId].paysTokens = _newPaysTokens;
tokenContracts[_bountyId] = HumanStandardToken(_newTokenContract);
BountyChanged(_bountyId); BountyChanged(_bountyId);
} }
``` ```
@ -405,13 +389,8 @@ function increasePayout(uint _bountyId, uint _newFulfillmentAmount, uint _value)
transferredAmountEqualsValue(_bountyId, _value) transferredAmountEqualsValue(_bountyId, _value)
{ {
bounties[_bountyId].balance += _value; bounties[_bountyId].balance += _value;
uint newOwedAmount = (bounties[_bountyId].owedAmount + require(bounties[_bountyId].balance >= _newFulfillmentAmount);
((_newFulfillmentAmount - bounties[_bountyId].fulfillmentAmount)
* (numAccepted[_bountyId] - numPaid[_bountyId])));
require(bounties[_bountyId].balance >= newOwedAmount);
bounties[_bountyId].owedAmount = newOwedAmount;
bounties[_bountyId].fulfillmentAmount = _newFulfillmentAmount; bounties[_bountyId].fulfillmentAmount = _newFulfillmentAmount;
ContributionAdded(_bountyId, msg.sender, _value);
PayoutIncreased(_bountyId, _newFulfillmentAmount); PayoutIncreased(_bountyId, _newFulfillmentAmount);
} }
``` ```
@ -424,10 +403,9 @@ function getFulfillment(uint _bountyId, uint _fulfillmentId)
constant constant
validateBountyArrayIndex(_bountyId) validateBountyArrayIndex(_bountyId)
validateFulfillmentArrayIndex(_bountyId, _fulfillmentId) validateFulfillmentArrayIndex(_bountyId, _fulfillmentId)
returns (bool, bool, address, string) returns (bool, address, string)
{ {
return (fulfillments[_bountyId][_fulfillmentId].paid, return (fulfillments[_bountyId][_fulfillmentId].accepted,
fulfillments[_bountyId][_fulfillmentId].accepted,
fulfillments[_bountyId][_fulfillmentId].fulfiller, fulfillments[_bountyId][_fulfillmentId].fulfiller,
fulfillments[_bountyId][_fulfillmentId].data); fulfillments[_bountyId][_fulfillmentId].data);
} }
@ -440,14 +418,13 @@ function getBounty(uint _bountyId)
public public
constant constant
validateBountyArrayIndex(_bountyId) validateBountyArrayIndex(_bountyId)
returns (address, uint, uint, bool, uint, uint, uint) returns (address, uint, uint, bool, uint, uint)
{ {
return (bounties[_bountyId].issuer, return (bounties[_bountyId].issuer,
bounties[_bountyId].deadline, bounties[_bountyId].deadline,
bounties[_bountyId].fulfillmentAmount, bounties[_bountyId].fulfillmentAmount,
bounties[_bountyId].paysTokens, bounties[_bountyId].paysTokens,
uint(bounties[_bountyId].bountyStage), uint(bounties[_bountyId].bountyStage),
bounties[_bountyId].owedAmount,
bounties[_bountyId].balance); bounties[_bountyId].balance);
} }
``` ```
@ -531,10 +508,7 @@ This is emitted when a given bounty is fulfilled
This is emitted when a given fulfillment is altered This is emitted when a given fulfillment is altered
```event FulfillmentAccepted(uint bountyId, address indexed fulfiller, uint256 indexed _fulfillmentId);``` ```event FulfillmentAccepted(uint bountyId, address indexed fulfiller, uint256 indexed _fulfillmentId);```
This is emitted when a given fulfillment for a given bounty is accepted This is emitted when a given fulfillment for a given bounty is accepted and paid
```event FulfillmentPaid(uint bountyId, address indexed fulfiller, uint256 indexed _fulfillmentId);```
This is emitted when a given fulfillment for a given bounty is paid
```event BountyKilled(uint bountyId);``` ```event BountyKilled(uint bountyId);```
This is emitted when a given bounty is killed This is emitted when a given bounty is killed