Skip to content
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

dao rewards distribution emission rate updates #848

Merged
merged 39 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0d3a5cc
passing RegisterRewardDenomMsg struct to register new denom
bekauz Jun 23, 2024
bad4ec1
wip: switching DenomRewardState to active/historic epoch configuration
bekauz Jun 29, 2024
61beee2
wip: transitioning epoch on update
bekauz Jun 30, 2024
575dc9c
wip: querying historic rewards & claims including multiple epochs
bekauz Jun 30, 2024
b48187c
setting zero emission duration to u64::MAX
bekauz Jul 7, 2024
965881b
move update_rewards fn to hooks.rs
bekauz Jul 7, 2024
39ef7df
fix double-claim; finish reward rate updating unit test; cleanup debu…
bekauz Jul 7, 2024
e9c7871
cleanup
bekauz Jul 14, 2024
d741f11
update readme; cleanup RewardEmissionRate impl
bekauz Jul 14, 2024
599abbb
regen schemas
bekauz Jul 15, 2024
9fedb85
renamed some stuff and cleaned up
NoahSaso Jul 18, 2024
edd0176
fixed some comments
NoahSaso Jul 18, 2024
675055e
updated comment and renamed function
NoahSaso Jul 18, 2024
6605e27
fixed epoch calculation
NoahSaso Jul 18, 2024
15b87e8
rearranged some code
NoahSaso Jul 18, 2024
3579170
reorganized more code
NoahSaso Jul 18, 2024
72694c0
updated README
NoahSaso Jul 18, 2024
b8e7f6e
renamed epoch config to epoch
NoahSaso Jul 19, 2024
a6a4f86
replaced historical epoch vector with just a rewards counter
NoahSaso Jul 19, 2024
78ce002
added ability to update config for a registered denom
NoahSaso Jul 19, 2024
025e260
added test
NoahSaso Jul 19, 2024
7573397
more cleanup
NoahSaso Jul 21, 2024
458ea1a
fixed test
NoahSaso Jul 21, 2024
6cda531
added comment
NoahSaso Jul 21, 2024
e326fcd
removed unused finish_block
NoahSaso Jul 21, 2024
008ae49
fixed transition_epoch so new epochs can change height vs. time durat…
NoahSaso Jul 21, 2024
22e0fe3
more cleanup
NoahSaso Jul 21, 2024
3918ebf
cleaned up fund logic
NoahSaso Jul 21, 2024
91a8420
added continuous field to denom config deciding how backfilled fundin…
NoahSaso Jul 21, 2024
fb99482
added ability to fund a native denom during registration
NoahSaso Jul 21, 2024
c7c11a8
improved test coverage
NoahSaso Jul 21, 2024
e6511cd
added pagination to list queries
NoahSaso Jul 21, 2024
ce8308e
allow duplicate denoms with different configs by creating unique ID f…
NoahSaso Jul 22, 2024
d71dcba
added explicit paused emission rate variant
NoahSaso Jul 22, 2024
cdba640
added explicit immediate emission rate variant
NoahSaso Jul 22, 2024
2e365ec
moved continuous to linear emission rate enum
NoahSaso Jul 22, 2024
6064a5d
default owner to instantiator if not provided
NoahSaso Jul 22, 2024
a383174
continuous cleanup
NoahSaso Jul 22, 2024
7143fcc
updated README
NoahSaso Jul 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 65 additions & 9 deletions contracts/distribution/dao-rewards-distributor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[![dao-rewards-distributor on crates.io](https://img.shields.io/crates/v/dao-rewards-distributor.svg?logo=rust)](https://crates.io/crates/dao-rewards-distributor)
[![docs.rs](https://img.shields.io/docsrs/dao-rewards-distributor?logo=docsdotrs)](https://docs.rs/dao-rewards-distributor/latest/cw20_stake_external_rewards/)

The `dao-rewards-distributor` works in conjuction with DAO voting modules to provide rewards over time for DAO members. The contract supports both cw20 and native Cosmos SDK tokens. The following voting power modules are supported:
The `dao-rewards-distributor` works in conjuction with DAO voting modules to provide rewards over time for DAO members. The contract supports both cw20 and native Cosmos SDK tokens. The following voting power modules are supported for deriving staking reward allocations:

- `dao-voting-cw4`: for membership or group based DAOs
- `dao-voting-cw20-staked`: for cw20 token based DAOs.
- `dao-voting-cw721-staked`: for NFT based DAOs.
Expand All @@ -13,19 +14,74 @@ NOTE: this contract is NOT AUDITED and is _experimental_. USE AT YOUR OWN RISK.

## Instantiation and Setup

The contract is instantiated with a number of parameters:
- `owner`: The owner of the contract. Is able to fund the contract and update the reward duration.
- `vp_contract`: A DAO DAO voting power module contract address, used to determine membership in the DAO over time.
- `hook_caller`: An optional contract that is allowed to call voting power change hooks. Often, as in `dao-voting-token-staked` and `dao-voting-cw721-staked` the vp_contract calls hooks for power change events, but sometimes they are separate. For example, the `cw4-group` contract is separate from the `dao-voting-cw4` contract and since the `cw4-group` contract fires the membership change events, it's address would be used as the `hook_caller`.
- `reward_denom`: the denomination of the reward token, can be either a cw20 or native token.
- `reward_duration`: the time period over which rewards are to be paid out in blocks.
The contract is instantiated with a very minimal state.
An optional `owner` can be specified. If it is not, the owner is set
to be the address instantiating the contract.

### Hooks setup

After instantiating the contract it is VITAL to setup the required hooks for it to work. This is because to pay out rewards accurately, this contract needs to know about staking or voting power changes in the DAO.

This can be achieved using the `add_hook` method on contracts that support voting power changes, which are:
This can be achieved using the `add_hook` method on contracts that support voting power changes, such as:

- `cw4-group`
- `dao-voting-cw721-staked`
- `dao-voting-token-staked`
- `cw20-stake`

Finally, the contract needs to be funded with a token matching the denom specified in the `reward_denom` field during instantiation. This can be achieved by calling the `fund` method on the `dao-rewards-distributor` smart contract, and sending along the appropriate funds.
### Registering a new reward denom

Only the `owner` can register new denoms for distribution.

Registering a denom for distribution expects the following config:

- `denom`, which can either be `Cw20` or `Native`
- `emission_rate`, which determines the `amount` of that denom to be distributed to all applicable addresses per `duration` of time. duration here may be declared in either time (seconds) or blocks. some example configurations may be:
- `1000udenom` per 500 blocks
- `1000udenom` per 24 hours
- `0udenom` per any duration which effectively pauses the rewards
- `vp_contract` address, which will be used to determine the total and relative address voting power for allocating the rewards in a pro-rata basis
- `hook_caller` address, which will be authorized to call back into this contract with any voting power event changes. Example of such events may be:
- user staking tokens
- user unstaking tokens
- user cw-721 state change event
- cw-4 membership change event
- optional `withdraw_destination` address to be used in cases where after shutting down the denom reward distribution unallocated tokens would be sent to. One example use case of this may be some subDAO.

A denom being registered does not mean that any rewards will be distributed. Instead, it enables that to happen by enabling the registered reward denom to be funded.

Currently, a single denom can only have one active distribution configuration.

### Funding the denom to be distributed

Anyone can fund a denom to be distributed as long as that denom
is registered.

If a denom is not registered and someone attempts to fund it, an error will be thrown.

Otherwise, the funded denom state is updated in a few ways.

First, the funded period duration is calculated based on the amount of tokens sent and the configured emission rate. For instance, if 100_000udenom were funded, and the configured emission rate is 1_000udenom per 100 blocks, we derive that there are 100_000/1_000 = 100 epochs funded, each of which contain 100 blocks. We therefore funded 10_000 blocks of rewards.

Then the active epoch end date is re-evaluated, depending on its current value:

- If the active epoch never expires, meaning no rewards are being distributed, we take the funded period duration and add it to the current block.
- If the active epoch expires in the future, then we extend the current deadline with the funded period duration.
- If the active epoch had already expired, then we re-start the rewards distribution by adding the funded period duration to the current block.

### Updating denom reward emission rate

Only the `owner` can update the reward emission rate.

Updating the denom reward emission rate archives the active reward epoch and starts a new one.

First, the currently active epoch is evaluated. We find the amount of tokens that were earned to this point per unit of voting power and save that in the current epoch as its total earned rewards per unit of voting power.
We then bump the last update with that of the current block, and transition into the new epoch.

The final (partial) amount of rewards distributed during the active reward epoch are added to `historical_earned_puvp` to ensure they can still be claimed. This historical value contains all rewards distributed during past epochs.

### Shutting down denom distribution

Only the `owner` can shutdown denom distribution.

Shutdown stops the denom from being distributed, calculates the amount of rewards that was allocated (and may or may not had been claimed yet), and claws that back to the `withdraw_address`.
Loading
Loading