-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
Standard Bounties #1081
Standard Bounties #1081
Conversation
EIPS/standard-bounties.md
Outdated
@@ -0,0 +1,122 @@ | |||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reformat using the standard format dictated in EIP-0 and EIP-X.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only difference was in the formatting of the header, correct? I've fixed it in standard-bounties.md
EIPS/eip-1081.md
Outdated
@@ -0,0 +1,123 @@ | |||
--- | |||
EIP: <to be assigned> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please set to 1081.
EIPS/eip-1081.md
Outdated
@@ -0,0 +1,123 @@ | |||
--- | |||
EIP: <to be assigned> | |||
Title: EIP-1081 Standard Bounties |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove EIP-1081 from the title.
EIPS/eip-1081.md
Outdated
EIP: <to be assigned> | ||
Title: EIP-1081 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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please provide a public discussion URL.
EIPS/eip-1081.md
Outdated
Status: Draft | ||
Type: Standards Track | ||
Category: ERC | ||
Created: created on 2018-05-14 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove 'created on'.
EIPS/eip-1081.md
Outdated
Type: Standards Track | ||
Category: ERC | ||
Created: created on 2018-05-14 | ||
Requires: EIP20 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove 'EIP'.
The Kauri team are currenly working on bounties.network integration and would like to make the following proposals to the EIP.
|
I'm strongly in favour of bringing back the optional arbiter address (0x0 if not used), as well as the deadline to moderate bounty draining/refunds. The other proposal about requiring approval for changing data is interesting but possibly prohibitive for issuers (right now we're seeing a significant need for arbiters to need to update the data throughout the process). @owocki do you have thoughts on this? |
strongly agree about the arbiter address. this will allow us at Gitcoin to do some really important stuff regarding auto-payout when a PR is merged.. etc |
My general concern with adding in the need for approval from changing data is that it forces the submission of your intention to be on-chain rather than stored elsewhere- is this a good thing? Forcing people to pay gas fees on this action is may actually be beneficial as a disincentive from over-intending to too many bounties |
So the flag for changing data is intended to be optional. The intention is that a user would be able to flag a bounty if they feel it is beneficial for them to do so to provide extra protection from the issuer changing requirements underneath them, (in this case, paying the gas fee is like paying an insurance premium) |
|
I believe we should be very intentional about the flagging/"submitting desire to fulfill" of bounties: if this is to live on-chain for some bounties, it should be there for all bounties (so that this information is easily shared among platforms). We've actually run into this issue somewhat, where bounties on Gitcoin have users claiming them, however they remain unclaimed when displayed on the Bounties Network (since the "claiming" is off-chain and stored on Gitcoin's servers). I believe we may make this "claiming" functionality extremely lightweight from a gas perspective (just flipping a bit in an address->bool mapping). On the topic of the |
I have added |
"I believe we should be very intentional about the flagging/"submitting desire to fulfill" of bounties: if this is to live on-chain for some bounties, it should be there for all bounties" - Agree that the flag should exist for all bounties, but a user 'flagging' a bounty should not be a compulsory prerequisite for fulfilling the bounty. They can then make a decision around if it is worth the additional gas cost in order to lock down the scope of the bounty. On the |
I think this makes sense In your design, who is the decider of correct submissions? In this version of the contract both the issuer and the arbiter have the right to accept submissions. If you believe the controller shouldn't be able to accept submissions alongside the arbiter (or drain the bounty) then yes, I believe that functionality can be included in a separate contract. |
EIPS/eip-1081.md
Outdated
@@ -0,0 +1,123 @@ | |||
--- | |||
EIP: 1081 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please lowercase these headers, as in eip-0 and eip-x.
@craigwilliams84 @joshorig how mandatory would it be for you guys to have this approve-data-change feature added? While I generally agree that issuers changing data drastically is bad manners and can lead to a dispute, should we forcefully stop them? I've begun implementing these changes and have realized that this approvals process would likely be so gas expensive that it wouldn't make sense. It would also let someone attack someone's bounty by submitting intention, thereby locking their This is compounded that the changes in data may actually just be additive, i.e. the inclusion of more links or specific details, which is a good thing for bounty fulfillers. My gut says we should let issuers change data as they desire, and rely on a dispute resolution system (like Delphi) to pay out fulfillers if they feel aggrieved (i.e. if bounty data was changed substantially after they publicly started work, and performed a significant portion of it). |
@mbeylin you raise valid points, likely dispute resolution is a better way to solve such an issue. It's not a mandatory feature for us it worth us looking at other ways to solve that particular issue |
@mbeylin As it currently stands, the spec is tightly coupled to a contract-per-bounty approach. For example, |
We have the concept of a 'topic' associated with bounties, and each topic has a defined set of moderators (who should be subject matter experts) that decide if a submissions is accurate and of a high enough quality. Currently we are in control of assigning moderators, but will move to a community based approach over time. |
@craigwilliams84 With regards to using a contract-per-bounty approach, there are a number of benefits, namely:
In terms of your moderator system, I believe this functionality should likely live within a separate contract, which then has the ability to be the "arbiter" and accept submissions. |
I wanted to share progress on this effort, as the contracts have fully implemented based on the needs specified in this thread. @owocki has requested that the contracts also be able to support ERC721 NFT tokens, however I've run into an issue when implementing this feature. Because NFTs are un-splittable, we can't calculate fractions for them like we might for ERC20 tokens being paid for a fulfillment which is shared by several participants (at various ratios). This has required us to change the fields on the There are several alternatives we can consider now so that we may move forward quickly (without letting this be a blocker for us). It's worth remembering that in this new architecture, migrating to new contracts is as easy as changing the
In my opinion the first of these options seems the most reasonable based on the needs we've heard from users, but I want to hear your thoughts as well @craigwilliams84 @joshorig |
My first reaction is to challenge this statement :
I dont see why this follows from
Why not just only accept whole integer payouts for ERC721 tokens, and ==================================================== Beyond that, if i was forced to choose: i think that multiple tokens are important. i also think that several fulfillers per fulfillment are important. my vote would be "we move forward without NFTs for now and keep the several fulfillers per fulfillment" |
@karelstriegel i'd love to get your guys' feedback on this standard. |
@owocki I'm happy to explain. Currently, the way that the payout amounts are entered is that upon acceptance of a fulfillment, the issuer of the bounty must send in the addresses of the particular tokens they want to pay out, along with the amount of the token being disbursed (two 1D arrays). However there's an issue: when a fulfillment is submitted it's possible that you'd have 2 fulfillers, each getting half of the credit for the submission. For fungible tokens this works well: if there is a submission with multiple fulfillers, it just divides the tokens up as best as it can among the fulfillers, and disburses them accordingly. However, in the case of NFTs, the This creates a serious issue: how should non fungible assets be handled in the case where there are multiple fulfillers? Should they just automatically be sent to the first fulfiller in the array? This seems like a bad solution. The only way I could foresee getting around this problem was doing away with the storage of the fractions (for splitting fulfillment credit), moving it into the JSON object on IPFS, and instead allowing fulfillers to disburse different token amounts to different participants (presumably following the credit splitting outlined in the submission). This would require specifically outlining how much each individual should receive in each token. This is a 2D array. |
makes sense to me. thanks for the thorough expalnation. my vote remains what it was above
|
We're looking into incorporating NFTs into Kauri right now, but it will be more along the lines of 'badges' received at certain milestones rather than something attached to a specific bounty. I vote to move forward without NFTs. |
I would go with the following option:
Allowing for multiple fulfillers seems to be essential, I'm not sure how well that lends itself to an NFT being the reward for a bounty. Seems like that needs some more thought. |
Great. I've finished updating the EIP to document these amendments and the |
Before we begin a code freeze and audit (so that we may deploy these new contracts as soon as possible), I would like to publicly ask one final time for review from other bounty platforms which haven't yet weighed in on this EIP (in no particular order):
If you are interested in employing standardized, cross platform bounties, now is your chance to have your voice heard before it's too late!!! |
After a fruitful code review on the Gitcoin livestream last week, some final fixes have been made to the contract, and it's finally ready for code freeze and audit. I believe now is a suitable time to remove the WIP status from this EIP and get it merged in as a draft. |
@Arachnid this EIP should now be ready for merging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
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).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.issuer
orarbiter
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 theissuer
.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 theissuer
or thearbiter
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 theissuer
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 theissuer
to change theissuer
,arbiter
,data
, anddeadline
fields of their bounty.changeIssuer(address _issuer)
: This may be called by theissuer
to change to a newissuer
if need bechangeArbiter(address _arbiter)
: This may be called by theissuer
to change to a newarbiter
if need bechangeData(string _data)
: This may be called by theissuer
to change just thedata
changeDeadline(uint _deadline)
: This may be called by theissuer
to change just thedeadline
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'sissuer
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)
: Forissuer
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 therefundableContribute
function may retreive their funds from the contract.Schemas
Persona Schema:
Bounty issuance
data
Schema:Bounty
fulfillment
data Schema: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 bountyissuer
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.