Tokenomics rewards (#802)
* Initial analysis * Implement core rewards distribution * Tests and refactoring for better testability * Feature gate ts-rs in mixnet-contract * No more floats * Fix performance calculation * Add migration * Bandwidth fix, reduce inflation pool size * Update tokenomics * Refactor rewarding and replace num crate * Address review comments * Cleanup, better test values * Simplify formula * Cleanup, add rewarding formulas to README * Address review comments * Cleanup rebase * [ci skip] Generate TS types * fmt Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>
This commit is contained in:
Vendored
+2
-2
@@ -75,7 +75,7 @@ impl<C> ValidatorCacheRefresher<C> {
|
||||
{
|
||||
let (mixnodes, gateways) = tokio::try_join!(
|
||||
self.nymd_client.get_mixnodes(),
|
||||
self.nymd_client.get_gateways()
|
||||
self.nymd_client.get_gateways(),
|
||||
)?;
|
||||
|
||||
let state_params = self.nymd_client.get_state_params().await?;
|
||||
@@ -83,7 +83,7 @@ impl<C> ValidatorCacheRefresher<C> {
|
||||
info!(
|
||||
"Updating validator cache. There are {} mixnodes and {} gateways",
|
||||
mixnodes.len(),
|
||||
gateways.len()
|
||||
gateways.len(),
|
||||
);
|
||||
|
||||
self.cache
|
||||
|
||||
@@ -93,6 +93,34 @@ impl<C> Client<C> {
|
||||
Ok(time)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_reward_pool(&self) -> Result<u128, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.0.read().await.get_reward_pool().await?)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.0.read().await.get_circulating_supply().await?)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_sybil_resistance_percent(&self) -> Result<u8, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.0.read().await.get_sybil_resistance_percent().await?)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_epoch_reward_percent(&self) -> Result<u8, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
Ok(self.0.read().await.get_epoch_reward_percent().await?)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::storage::models::{
|
||||
};
|
||||
use crate::storage::ValidatorApiStorage;
|
||||
use log::{error, info};
|
||||
use mixnet_contract::mixnode::NodeRewardParams;
|
||||
use mixnet_contract::{ExecuteMsg, IdentityKey};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
@@ -48,6 +49,19 @@ pub(crate) struct MixnodeToReward {
|
||||
|
||||
/// Total number of individual addresses that have delegated to this particular node
|
||||
pub(crate) total_delegations: usize,
|
||||
/// Node absolute uptime over total active set uptime
|
||||
params: Option<NodeRewardParams>,
|
||||
}
|
||||
|
||||
impl MixnodeToReward {
|
||||
/// Somewhat clumsy way of feature gatting tokenomics payments. In a tokenomics scenario this will never be None at reward time. We levarage that to Into a different ExecuteMsg variant
|
||||
fn params(&self) -> Option<NodeRewardParams> {
|
||||
if cfg!(feature = "tokenomics") {
|
||||
self.params
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct FailedMixnodeRewardChunkDetails {
|
||||
@@ -62,9 +76,16 @@ pub(crate) struct FailureData {
|
||||
|
||||
impl<'a> From<&'a MixnodeToReward> for ExecuteMsg {
|
||||
fn from(node: &MixnodeToReward) -> Self {
|
||||
ExecuteMsg::RewardMixnode {
|
||||
identity: node.identity.clone(),
|
||||
uptime: node.uptime.u8() as u32,
|
||||
if let Some(params) = node.params() {
|
||||
ExecuteMsg::RewardMixnodeV2 {
|
||||
identity: node.identity.clone(),
|
||||
params,
|
||||
}
|
||||
} else {
|
||||
ExecuteMsg::RewardMixnode {
|
||||
identity: node.identity.clone(),
|
||||
uptime: node.uptime.u8() as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,12 +206,13 @@ impl Rewarder {
|
||||
// by people hesitating to delegate to nodes without them and thus those nodes disappearing
|
||||
// from the active set (once introduced)
|
||||
let mixnode_delegators = self.produce_active_mixnode_delegators_map().await?;
|
||||
let state = self.nymd_client.get_state_params().await?;
|
||||
|
||||
// 1. go through all active mixnodes
|
||||
// 2. filter out nodes that are currently not in the active set (as `mixnode_delegators` was obtained by
|
||||
// querying the validator)
|
||||
// 3. determine uptime and attach delegators count
|
||||
let eligible_nodes = active_mixnodes
|
||||
let mut eligible_nodes: Vec<MixnodeToReward> = active_mixnodes
|
||||
.iter()
|
||||
.filter_map(|mix| {
|
||||
mixnode_delegators
|
||||
@@ -199,11 +221,39 @@ impl Rewarder {
|
||||
identity: mix.identity.clone(),
|
||||
uptime: mix.last_day,
|
||||
total_delegations,
|
||||
params: None,
|
||||
})
|
||||
})
|
||||
.filter(|node| node.uptime.u8() > 0)
|
||||
.collect();
|
||||
|
||||
if cfg!(feature = "tokenomics") {
|
||||
let reward_pool = self.nymd_client.get_reward_pool().await?;
|
||||
let circulating_supply = self.nymd_client.get_circulating_supply().await?;
|
||||
let sybil_resistance_percent = self.nymd_client.get_sybil_resistance_percent().await?;
|
||||
let epoch_reward_percent = self.nymd_client.get_epoch_reward_percent().await?;
|
||||
let k = state.mixnode_active_set_size;
|
||||
let period_reward_pool = (reward_pool / 100) * epoch_reward_percent as u128;
|
||||
|
||||
info!("Rewarding pool stats");
|
||||
info!("-- Reward pool: {} unym", reward_pool);
|
||||
info!("---- Epoch reward pool: {} unym", period_reward_pool);
|
||||
info!("-- Circulating supply: {} unym", circulating_supply);
|
||||
|
||||
for mix in eligible_nodes.iter_mut() {
|
||||
mix.params = Some(NodeRewardParams::new(
|
||||
period_reward_pool,
|
||||
k.into(),
|
||||
0,
|
||||
circulating_supply,
|
||||
mix.uptime.u8().into(),
|
||||
sybil_resistance_percent,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
info!("Tokenomics feature is OFF");
|
||||
}
|
||||
|
||||
Ok(eligible_nodes)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user