New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERC-1070 Standard Bounties #1070

Closed
mbeylin opened this Issue May 8, 2018 · 2 comments

Comments

Projects
None yet
3 participants
@mbeylin
Contributor

mbeylin commented May 8, 2018

EIP: <to be assigned>
Title: ERC-1070 Standard Bounties
Authors: Mark Beylin <mark.beylin@consensys.net>, Kevin Owocki <kevin.owocki@consensys.net>, Ricardo Guilherme Schmidt (@3esmit)
Discussions-to: <mark.beylin@consensys.net>
Status: Draft
Type: Standards Track
Category: ERC
Created: created on 2018-05-08
Requires: EIP20

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: a controller 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 controller 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 _controller, string _data): 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 controller 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 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 controller to drain a bounty of it's funds, if the need should arise.
  • changeBounty(address _controller, string _data): This may be called by the controller to change the controller or data field of their bounty.
  • changeController(address _controller): This may be called by the controller to change to a new controller if need be
  • changeData(string _data): This may be called by the controller to change just the data

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 controller 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 controllers 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, those which employed the refundableContribute function may retreive 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
    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 issuers 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.

@mbeylin mbeylin changed the title from ERC-1070 StandardBounties to ERC-1070 Standard Bounties May 8, 2018

@owocki

This comment has been minimized.

Show comment
Hide comment
@owocki

owocki May 8, 2018

Hi from gitcoin.co -- Can confirm, we rare using StandardBounties on our platform

owocki commented May 8, 2018

Hi from gitcoin.co -- Can confirm, we rare using StandardBounties on our platform

@Arachnid

This comment has been minimized.

Show comment
Hide comment
@Arachnid

Arachnid May 8, 2018

Collaborator

I'd suggest opening this as a PR, unless you want a lot of feedback before writing up a draft.

Collaborator

Arachnid commented May 8, 2018

I'd suggest opening this as a PR, unless you want a lot of feedback before writing up a draft.

@mbeylin mbeylin closed this May 8, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment