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

feat: NTRN-308 - Implement burn-based vesting for treasury #15

Merged
merged 3 commits into from
Jan 13, 2023

Conversation

albertandrejev
Copy link
Member

@albertandrejev albertandrejev commented Dec 19, 2022

Treasury tokens are vested based on on-chain activity: burnt_tokens * a_multiplier. The multiplier is an linear function of the supply: while initially, one burnt tokens equals multiple NTRN tokens made liquid, the flow of new tokens into the Treasury progressively slows down until the tokens supply is exhausted and the tokenomy becomes deflationary.

Related PRs:

Depends on:

@albertandrejev albertandrejev marked this pull request as draft December 19, 2022 14:26
@albertandrejev albertandrejev marked this pull request as ready for review December 22, 2022 14:34
@albertandrejev albertandrejev force-pushed the feat/NTRN-308-treasure-vesting branch 2 times, most recently from b2eaad7 to 4493411 Compare December 23, 2022 19:31
Copy link
Collaborator

@pr0n00gler pr0n00gler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me but the PR is blocked by neutron-org/neutron#117, so I'm waiting for it to be reviewed, merged and implementation of querying of TotalBurnedNeutronsAmount in this PR

@quasisamurai
Copy link
Contributor

lgtm, waiting for this


pub fn get_burned_coins(deps: Deps<InterchainQueries>, denom: &String) -> StdResult<Uint128> {
let burned_coins = query_total_burned_neutrons(deps).map_err(|_err| {
println!("{:?}", _err);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug print?

return Ok(Uint128::zero());
}

let current_balance = Decimal::from_atomics(current_balance, 0).map_err(|err| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why zero decimal places?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to simplify calculations

}

let current_balance = Decimal::from_atomics(current_balance, 0).map_err(|err| {
StdError::generic_err(format!("Unable to convert Uint128 to Decimal. {}", err))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe {:?}

image

contracts/treasury/Cargo.toml Outdated Show resolved Hide resolved
});
resp = resp.add_message(msg)
}
if burned_tokens.is_ok() && !current_balance.is_zero() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe if burned_tokens returns StdError we should return error from contract, since it's unexpected really?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while it's meaningful to return no funds to distribute on current_balance.is_zero(), in case of an error the error should be returned indeed, because otherwise we wouldn't be able to figure out why the contract says no funds to distribute whereas there are funds

Ok(())
}

pub fn create_distribution_response(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this, but: Is this responsibility of vesting - to operate on level of Response? how about returning here just an array of messages?

contracts/treasury/src/vesting.rs Outdated Show resolved Hide resolved
});
}
let last_burned_coins = LAST_BURNED_COINS_AMOUNT.load(deps.storage)?;
let burned_tokens = get_burned_coins(deps.as_ref(), &denom);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename burned_tokens -> burned_coins for identity

});
resp = resp.add_message(msg)
}
if burned_tokens.is_ok() && !current_balance.is_zero() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while it's meaningful to return no funds to distribute on current_balance.is_zero(), in case of an error the error should be returned indeed, because otherwise we wouldn't be able to figure out why the contract says no funds to distribute whereas there are funds

@albertandrejev albertandrejev force-pushed the feat/NTRN-308-treasure-vesting branch 2 times, most recently from a3fbc4d to 236b306 Compare January 12, 2023 23:09
@albertandrejev albertandrejev force-pushed the feat/NTRN-308-treasure-vesting branch from 236b306 to 306c06e Compare January 13, 2023 12:24
@@ -206,14 +218,17 @@ pub fn execute_update_config(
if let Some(security_dao_address) = security_dao_address {
config.security_dao_address = deps.api.addr_validate(security_dao_address.as_str())?;
}
if let Some(distribution_rate) = distribution_rate {
if let Some(distribution_rate) = distribution_params.distribution_rate {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we do not validate distribution_rate in init message?

/// Function calculates how many coins should be released for the current period
/// based on the current balance and the number of coins burned for the period
/// Implemented vesting function is linear and is defined as: y=x/vesting_denominator
/// In order to optimize the function, we use the following formula: y=x - (vesting_denominator-1 / vesting_denominator)^<coins for period> * x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think its a cleaner ((vesting_denominator-1) / vesting_denominator). One more brackets level

pub fn safe_burned_coins_for_period(
burned_coins: Uint128,
last_burned_coins: Uint128,
) -> StdResult<u32> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason to use u32

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decimal.checked_pow works with u32 only

@zavgorodnii zavgorodnii merged commit 41a4787 into main Jan 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants