Skip to content

Commit

Permalink
Calculate rewards pot per proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsanchezq committed Oct 18, 2021
1 parent e25a309 commit 8894e5d
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 11 deletions.
27 changes: 23 additions & 4 deletions src/community_advisors/models/de.rs
@@ -1,7 +1,5 @@
use serde::Deserialize;

use vit_servicing_station_lib::db::models::community_advisors_reviews::ReviewTag;

#[derive(Deserialize)]
pub struct AdvisorReviewRow {
pub proposal_id: String,
Expand All @@ -22,9 +20,30 @@ pub struct AdvisorReviewRow {
#[serde(alias = "Auditability Rating")]
pub auditability_rating: u8,
#[serde(alias = "Excellent")]
pub excellent: u32,
excellent: bool,
#[serde(alias = "Good")]
pub good: u32,
good: bool,
}

pub enum ReviewScore {
Excellent,
Good,
}

impl AdvisorReviewRow {
pub fn score(&self) -> ReviewScore {
match (self.excellent, self.good) {
(true, false) => ReviewScore::Excellent,
(false, true) => ReviewScore::Excellent,
_ => {
// This should never happen
panic!(
"Invalid combination of scores from assessor {} for proposal {}",
self.assessor, self.proposal_id
)
}
}
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion src/community_advisors/models/mod.rs
@@ -1,5 +1,5 @@
mod de;
mod tags;

pub use de::AdvisorReviewRow;
pub use de::{AdvisorReviewRow, ReviewScore};
pub use tags::TagsMap;
13 changes: 9 additions & 4 deletions src/rewards/ca/funding.rs
Expand Up @@ -25,21 +25,26 @@ impl FundSetting {
pub fn total_funds(&self) -> Funds {
self.total
}

#[inline]
pub fn funds_per_proposal(&self, number_of_proposals: u64) -> Funds {
self.total / Funds::from(number_of_proposals)
}
}

#[derive(Deserialize)]
pub struct ProposalRewardSlots {
pub excellent_slots: usize,
pub good_slots: usize,
pub filled_slots: usize,
pub excellent_slots: u64,
pub good_slots: u64,
pub filled_slots: u64,
}

impl Default for ProposalRewardSlots {
fn default() -> Self {
Self {
excellent_slots: 12,
good_slots: 4,
filled_slots: 35,
filled_slots: 36,
}
}
}
2 changes: 1 addition & 1 deletion src/rewards/ca/lottery.rs
Expand Up @@ -14,6 +14,6 @@ pub fn lottery_winner(distribution: &TicketsDistribution) -> Ca {
.iter()
.map(|(ca, &tickets)| (ca.clone(), tickets))
.collect();
let mut dist = WeightedIndex::new(items.iter().map(|x| x.1)).unwrap();
let dist = WeightedIndex::new(items.iter().map(|x| x.1)).unwrap();
items[dist.sample(&mut rng)].0.clone()
}
74 changes: 73 additions & 1 deletion src/rewards/ca/mod.rs
@@ -1,7 +1,79 @@
mod funding;
mod lottery;

use serde::Deserialize;
use crate::community_advisors::models::{AdvisorReviewRow, ReviewScore};
use crate::rewards::ca::funding::{Funds, ProposalRewardSlots};
use std::collections::HashMap;

pub use funding::FundSetting;

pub type Ca = String;
pub type ProposalId = String;

pub type ProposalsRewards = HashMap<ProposalId, Funds>;
pub type CaRewards = HashMap<Ca, Funds>;
pub type ProposalsReviews = HashMap<ProposalId, Vec<AdvisorReviewRow>>;

enum ProposalRewardsState {
// Proposal has the exact quantity reviews to be rewarded
Exact,
// Proposal has less reviews as needed so some of the funds should go back into the rewards pool
Unfilled(Funds),
//
OverLoaded,
}

fn proposal_rewards_state(
proposal_reviews: &[AdvisorReviewRow],
proposal_fund: Funds,
rewards_slots: &ProposalRewardSlots,
) -> ProposalRewardsState {
let filled_slots: u64 = proposal_reviews
.iter()
.map(|review| match review.score() {
ReviewScore::Excellent => rewards_slots.excellent_slots,
ReviewScore::Good => rewards_slots.good_slots,
})
.sum();

if filled_slots < rewards_slots.filled_slots {
let unfilled_funds =
proposal_fund * (Funds::from(filled_slots) / Funds::from(rewards_slots.filled_slots));
ProposalRewardsState::Unfilled(unfilled_funds)
} else if filled_slots > rewards_slots.filled_slots {
ProposalRewardsState::OverLoaded
} else {
ProposalRewardsState::Exact
}
}

pub fn calculate_funds_per_proposal(
funding: &FundSetting,
proposal_reviews: &ProposalsReviews,
rewards_slots: &ProposalRewardSlots,
) -> ProposalsRewards {
let per_proposal_reward = funding.funds_per_proposal(proposal_reviews.len() as u64);
// proportionally split rewards
let mut rewards: ProposalsRewards = proposal_reviews
.keys()
.cloned()
.zip(std::iter::repeat(per_proposal_reward))
.collect();

// check rewards and split extra until there is no more to split
let underbudget_funds: Funds = proposal_reviews
.iter()
.map(|(id, reviews)| {
match proposal_rewards_state(reviews, per_proposal_reward, rewards_slots) {
ProposalRewardsState::Unfilled(extra_funds) => extra_funds,
_ => Funds::from(0u64),
}
})
.sum();

let underbudget_rewards = underbudget_funds / Funds::from(proposal_reviews.len() as u64);
rewards.values_mut().for_each(|v| {
*v += underbudget_rewards;
});
rewards
}

0 comments on commit 8894e5d

Please sign in to comment.