openzeppelin-contracts icon indicating copy to clipboard operation
openzeppelin-contracts copied to clipboard

Include a RewardDistribution Contract

Open mikeki opened this issue 3 years ago • 17 comments

🧐 Motivation

Many new projects in crypto are distributing tokens or creating their business models on top of a reward distribution contract, as initially done by synthetix. There's currently no 'official' contract that could be used for that, and I think it would be a great addition to the open zeppelin library

📝 Details

mikeki avatar Jan 07 '21 07:01 mikeki

We already have a PaymentSplitter contract, that is designed to do that for ETH (native token). We could just as well have an equivalent contract that deals with ERC20 tokens.

Would that meet your requirements? If so, we could definitely consider adding it.

Amxx avatar Jan 07 '21 12:01 Amxx

Thanks for the suggestion @mikeki. Can you share the contract that is used by Synthetix, or a similar one?

I think the requirements are slightly different to PaymentSplitter.

frangio avatar Jan 07 '21 16:01 frangio

I will take a look at PaymentSplitter, but they are probably different requirements, since the ones used widely on DeFi right now is also a Staking pool which distributes rewards according to the share of staked tokens in the pool.

This is the current Synthetix code, which at this point is very unique to their product, but might be a good place to get inspiration, since they've been working on it for quite a while now.

There's also the Yam Finance code, which is the pool that most DeFi projects started cloning. IMO it's very RAW, it could be a bit better organized.

I also ran into this other codebase which looks pretty well organized, although it seems like it was created with a different purpose in mind, but perhaps it could be adapted (Or perhaps it could be modularized to satisfy different needs)

mikeki avatar Jan 08 '21 03:01 mikeki

Thank you for all the links @mikeki. For licensing reasons we will probably prefer that any contracts for OpenZeppelin Contracts be written from scratch, but taking inspiration from these other protocols is fine.

We're interested in this feature but we will want to carefully design the solution. I think a good place to start is for someone to propose what contract we should add (possibly an ERC20 extension?), and a minimal interface for this contract.

frangio avatar Jan 12 '21 19:01 frangio

I already did this guys. I combined the ERC721 + PaymentSplitter for my first drop. I just forked and working on a PR to the ERC721 extensions folder since I feel like it is more that that a new Payment contract. I feel like simply calling it ERC721PaymentSplitter will be good enough for SEO.

hanselb avatar Feb 15 '22 18:02 hanselb

@hanselb It sounds unrelated to this issue. Before opening a PR please propose your contract in a new issue.

frangio avatar Feb 17 '22 21:02 frangio

@frangio just to make sure I understood the scope: We are trying to find an official way to distribute rewards among token holders in a transparent way. I am certain we can accomplish this with ERC721 + ERC721Enumerable + PaymentSplitter

In my implementation I extend ERC721Enumerable and use most of the functions of PaymentSplitter but remove payees[] and make _totalShares a function that returns the ERC721Enumerable's totalSupply.

This allows me to have two methods release(tokenId) and release(account) to distribute payment using ownerOf and tokenOfOwnerByIndex() internally. I also handle releasing any _pendingPayment(tokenId) on transfer or leaving it for future claim based on_releaseOnTranser prop which can be set in the constructor for ERC721PaymentSplitter

Please let me know if this is not in scope for this issue. I can definitely create a new issue for this. I think this extremely needed in the space for creators who wish to give back to their communities and I see a lot of external systems created to do this.

hanselb avatar Feb 18 '22 01:02 hanselb

I believe what you're describing is about "discrete" rewards where you want one payment (or a series of separate payments) to get split among token holders.

This issue is slightly different, it's about a reward pool that continuously drips rewards to the token holders.

frangio avatar Feb 18 '22 02:02 frangio

Anything you deposit onto the ERC721PaymentSplitter contract get's split among the holders equally and the balance is kept on the contract itself. I don't fully understand "continuously drips" does this mean that if they want to distribute 100 ETH total, they will slowly release that into the reward pool or is it more on an individual holder level? ERC721PaymentSplitter makes the rewards owed to holder available the moment it is deposited into the contract. I am using it to distribute Music Royalties and also give back a % of minting and resale to the holders right at the moment it happens.

hanselb avatar Feb 18 '22 16:02 hanselb

What I mean is you could deposit 100 ETH in a contract and configure the reward pool so they are distributed slowly over the course of 6 months, for example.

frangio avatar Feb 18 '22 18:02 frangio

I see, I have created a new issue for ERC721PaymentSplitter you can find it below. https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3201

Maybe for this issue we could use some of the PullPayment patterns inside the ERC721 to do the slow leak of the ETH https://docs.openzeppelin.com/contracts/4.x/api/security#PullPayment

hanselb avatar Feb 18 '22 21:02 hanselb

I'm very interested in an official implementation along the lines of what @frangio has described.

PrimeDominus avatar Apr 01 '22 03:04 PrimeDominus

@PrimeDominus Have you looked at other implementations of this concept across DeFi projects? Did you consider reusing them? Is there something in particular that an OpenZeppelin implementation should aim for?

frangio avatar Apr 07 '22 23:04 frangio

@frangio yes. Aside from the ones mentioned in this issue already, other examples I've seen are https://github.com/Seedifyfund/Launchpad-smart-contract/blob/main/contracts/SeedifyFund/SeedifyFundBNB.sol and https://github.com/MaxosLLC/LaunchPools/blob/main/contracts/StakeVault.sol

While the above appear to mostly do what's needed, on the surface it looks like they're written by someone relatively new to Solidity, and the first one doesn't state a license.

There's a good sense of reassurance when utilising contracts from OpenZeppelin.

A model that's been very successful and also seems to alleviate regulatory concerns is the Initial Stake Pool Offering (ISPO) model. Thus far, this has only happened on Cardano, and they have their contracts ready for reuse.

I'd love to be able to do something similar on Ethereum.

PrimeDominus avatar Apr 08 '22 03:04 PrimeDominus

Hey, @frangio any update on this? I'm looking at building this exact thing for a P2E project that I'm involved with and would definitely appreciate being able to use an OpenZeppelin implementation instead of a custom solution. We're using OZ for our ERC20, ERC721, and ERC1155 contracts already.

In my opinion, the implementation should aim for:

  • The ability to stake an arbitrary amount of an ERC20 token to a pool (i.e. create a staking position)
  • Increase/Decrease/Remove Staking Position
  • An ERC20 reward distribution mechanism, where each staker earns a share of the distribution proportional to their share of the overall pool -- ideally, the ERC20 you stake and the ERC20 you earn can be independent for enhanced staking reward flexibility
  • Be able to change the reward allocation, pause reward distribution, and other QoL admin functions

c194 avatar Apr 24 '22 13:04 c194

The approach described by @c194 would be great.

Another thing to consider, though I admittedly haven't thought this through, is to enable staking ETH itself, albeit since that would currently be going from PoW to a staking mechanism, maybe a wrapped-ETH for staking could be used for staking deposits.

PrimeDominus avatar May 03 '22 05:05 PrimeDominus

We're looking into this but still can't make any promises. We haven't settled on the right set of features and design.

frangio avatar May 06 '22 21:05 frangio