---
eip: 1081
title: Standard Bounties
author: Mark Beylin <mark.beylin@consensys.net>, Kevin Owocki <kevin.owocki@consensys.net>, Ricardo Guilherme Schmidt (@3esmit)
discussions-to: https://gitter.im/bounties-network/Lobby
status: Stagnant
type: Standards Track
category: ERC
created: 2018-05-14
requires: 20
---
   
## Simple Summary
A standard contract and interface for issuing bounties on Ethereum, usable for any type of task, paying in any ERC20 token or in ETH.

## Abstract
In order to encourage cross-platform interoperability of bounties on Ethereum, and for easier reputational tracking, StandardBounties can facilitate the administration of funds in exchange for deliverables corresponding to a completed task, in a publicly auditable and immutable fashion.

## Motivation
In the absence of a standard for bounties on Ethereum, it would be difficult for platforms to collaborate and share the bounties which users create (thereby recreating the walled gardens which currently exist on Web2.0 task outsourcing platforms). A standardization of these interactions across task types also makes it far easier to track various reputational metrics (such as how frequently you pay for completed submissions, or how frequently your work gets accepted).

## Specification
After studying bounties as they've existed for thousands of years (and after implementing and processing over 300 of them on main-net in beta), we've discovered that there are 3 core steps to every bounty:
- a bounty is **issued**: an `issuer` specifies the requirements for the task, describing the desired outcome, and how much they would be willing to pay for the completion of that task (denoted in one or several tokens).
- a bounty is **fulfilled**: a bounty `fulfiller` may see the bounty, complete the task, and produce a deliverable which is itself the desired outcome of the task, or simply a record that it was completed. Hashes of these deliverables should be stored immutably on-chain, to serve as proof after the fact.
- a fulfillment is **accepted**: a bounty `issuer` or `arbiter` may select one or more submissions to be accepted, thereby releasing payment to the bounty fulfiller(s), and transferring ownership over the given deliverable to the `issuer`.

To implement these steps, a number of functions are needed:
- `initializeBounty(address _issuer, address _arbiter, string _data, uint _deadline)`: This is used when deploying a new StandardBounty contract, and is particularly useful when applying the proxy design pattern, whereby bounties cannot be initialized in their constructors. Here, the data string should represent an IPFS hash, corresponding to a JSON object which conforms to the schema (described below).
- `fulfillBounty(address[] _fulfillers, uint[] _numerators, uint _denomenator, string _data)`: This is called to submit a fulfillment, submitting a string representing an IPFS hash which contains the deliverable for the bounty. Initially fulfillments could only be submitted by one individual at a time, however users consistently told us they desired to be able to collaborate on fulfillments, thereby allowing the credit for submissions to be shared by several parties. The lines along which eventual payouts are split are determined by the fractions of the submission credited to each fulfiller (using the array of numerators and single denominator). Here, a bounty platform may also include themselves as a collaborator to collect a small fee for matching the bounty with fulfillers.
- `acceptFulfillment(uint _fulfillmentId, StandardToken[] _payoutTokens, uint[] _tokenAmounts)`: This is called by the `issuer` or the `arbiter` to pay out a given fulfillment, using an array of tokens, and an array of amounts of each token to be split among the contributors. This allows for the bounty payout amount to move as it needs to based on incoming contributions (which may be transferred directly to the contract address). It also allows for the easy splitting of a given bounty's balance among several fulfillments, if the need should arise.
   - `drainBounty(StandardToken[] _payoutTokens)`: This may be called by the `issuer` to drain a bounty of it's funds, if the need should arise.
- `changeBounty(address _issuer, address _arbiter, string _data, uint _deadline)`: This may be called by the `issuer` to change the `issuer`, `arbiter`, `data`, and `deadline` fields of their bounty.
- `changeIssuer(address _issuer)`: This may be called by the `issuer` to change to a new `issuer` if need be
- `changeArbiter(address _arbiter)`: This may be called by the `issuer` to change to a new `arbiter` if need be
- `changeData(string _data)`: This may be called by the `issuer` to change just the `data`
- `changeDeadline(uint _deadline)`: This may be called by the `issuer` to change just the `deadline`

Optional Functions:
- `acceptAndFulfill(address[] _fulfillers, uint[] _numerators, uint _denomenator, string _data, StandardToken[] _payoutTokens, uint[] _tokenAmounts)`: During the course of the development of this standard, we discovered the desire for fulfillers to avoid paying gas fees on their own, entrusting the bounty's `issuer` to make the submission for them, and at the same time accept it. This is useful since it still immutably stores the exchange of tokens for completed work, but avoids the need for new bounty fulfillers to have any ETH to pay for gas costs in advance of their earnings.
- `changeMasterCopy(StandardBounty _masterCopy)`: For `issuer`s to be able to change the masterCopy which their proxy contract relies on, if the proxy design pattern is being employed.
- `refundableContribute(uint[] _amounts, StandardToken[] _tokens)`: While non-refundable contributions may be sent to a bounty simply by transferring those tokens to the address where it resides, one may also desire to contribute to a bounty with the option to refund their contribution, should the bounty never receive a correct submission which is paid out.
`refundContribution(uint _contributionId)`: If a bounty hasn't yet paid out to any correct submissions and is past it's deadline, those individuals who employed the `refundableContribute` function may retrieve their funds from the contract.

**Schemas**
Persona Schema:
```
{
   name: // optional - A string representing the name of the persona
   email: // optional - A string representing the preferred contact email of the persona
   githubUsername: // optional - A string representing the github username of the persona
   address: // required - A string web3 address of the persona
}
```
Bounty issuance `data` Schema:
```
{
  payload: {
    title: // A string representing the title of the bounty
    description: // A string representing the description of the bounty, including all requirements
    issuer: {
       // persona for the issuer of the bounty
    },
    funders:[
       // array of personas of those who funded the issue.
    ],
    categories: // an array of strings, representing the categories of tasks which are being requested
    tags: // an array of tags, representing various attributes of the bounty
    created: // the timestamp in seconds when the bounty was created
    tokenSymbol: // the symbol for the token which the bounty pays out
    tokenAddress: // the address for the token which the bounty pays out (0x0 if ETH)

    // ------- add optional fields here -------
    sourceFileName: // A string representing the name of the file
    sourceFileHash: // The IPFS hash of the file associated with the bounty
    sourceDirectoryHash: // The IPFS hash of the directory which can be used to access the file
    webReferenceURL: // The link to a relevant web reference (ie github issue)
  },
  meta: {
    platform: // a string representing the original posting platform (ie 'gitcoin')
    schemaVersion: // a string representing the version number (ie '0.1')
    schemaName: // a string representing the name of the schema (ie 'standardSchema' or 'gitcoinSchema')
  }
}
```
Bounty `fulfillment` data Schema:

```
{
  payload: {
    description: // A string representing the description of the fulfillment, and any necessary links to works
    sourceFileName: // A string representing the name of the file being submitted
    sourceFileHash: // A string representing the IPFS hash of the file being submitted
    sourceDirectoryHash: // A string representing the IPFS hash of the directory which holds the file being submitted
    fulfillers: {
      // personas for the individuals whose work is being submitted
    }

    // ------- add optional fields here -------
  },
  meta: {
    platform: // a string representing the original posting platform (ie 'gitcoin')
    schemaVersion: // a string representing the version number (ie '0.1')
    schemaName: // a string representing the name of the schema (ie 'standardSchema' or 'gitcoinSchema')
  }
}
```
## Rationale
The development of this standard began a year ago, with the goal of encouraging interoperability among bounty implementations on Ethereum. The initial version had significantly more restrictions: a bounty's `data` could not be changed after issuance (it seemed unfair for bounty `issuer`s to change the requirements after work is underway), and the bounty payout could not be changed (all funds needed to be deposited in the bounty contract before it could accept submissions). 

The initial version was also far less extensible, and only allowed for fixed payments to a given set of fulfillments. This new version makes it possible for funds to be split among several correct submissions, for submissions to be shared among several contributors, and for payouts to not only be in a single token as before, but in as many tokens as the `issuer` of the bounty desires. These design decisions were made after the 8+ months which Gitcoin, the Bounties Network, and Status Open Bounty have been live and meaningfully facilitating bounties for repositories in the Web3.0 ecosystem.

## Test Cases
Tests for our implementation can be found here: https://github.com/Bounties-Network/StandardBounties/tree/develop/test

## Implementation
A reference implementation can be found here: https://github.com/Bounties-Network/StandardBounties/blob/develop/contracts/StandardBounty.sol
**Although this code has been tested, it has not yet been audited or bug-bountied, so we cannot make any assertions about it's correctness, nor can we presently encourage it's use to hold funds on the Ethereum mainnet.**

## Copyright
Copyright and related rights waived via [CC0](../LICENSE.md).
