Skip to content

Commit

Permalink
Feature/plmc 239 end 2 end test (#68)
Browse files Browse the repository at this point in the history
* feat: for testing purposes let's assume 1 USDT = 1USD

* wip

* wip: align TestBid creation

* wip: switch to stable compiler

* test: check the remainder

* feat(244): move to rust stable

* Update rust-toolchain.toml

Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

* chore(244): move dep to workspace

* fix: remove unstable feature

* wip: check the ct amount

* feat: restore assert_matches macro

* test: add the remainder round from excel

* test: add more dbg outputs

* refactor: split the fees calculation login in several fn

* test: cleanup debug artefacts

* feat: calculate the CT amount in CT directly

* fix: use the Y from the KH

* feat: just return the total_fee_weight

* doc: specify the denomination of the pot

* test: restore the assert_matches macro

* git merge --squash -Xours origin/main

Squashed commit of the following:

commit a71eff7
Author: Juan Ignacio Rios <juani.rios.99@gmail.com>
Date:   Mon Aug 14 16:20:48 2023 +0200

    feat(243): Remove T::StorageItemId and replace it with hardcoded u32

commit 368abd9
Author: Juan Ignacio Rios <juani.rios.99@gmail.com>
Date:   Mon Aug 14 16:20:48 2023 +0200

    feat(249): Remove Option from Multipliers

    feat(249): Option no longer required for multipliers

    fix(243): rebase error

    chore(243): add import

    feat(245): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual release implemented and tested

    feat(247): automatic release implemented and tested

    feat(247): automatic release implemented and tested

    feat(248): manual release implemented and tested

    feat(248): automatic release implemented and tested

    wip

    feat(242): small optimization

    chore(242): fmt

    feat(242): change week to day conversion on config type

    feat(242): small changes from Leonardo's feedback

    Update pallets/funding/src/types.rs

    Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

    feat(244): linear increase of duration based on vesting

    wip

commit e576cdc
Author: Juan Ignacio Rios <54085674+JuaniRios@users.noreply.github.com>
Date:   Fri Aug 25 10:39:03 2023 +0100

    fix(243): rebase error (#72)

    chore(243): add import

    feat(245): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual release implemented and tested

    feat(247): automatic release implemented and tested

    feat(247): automatic release implemented and tested

    feat(248): manual release implemented and tested

    feat(248): automatic release implemented and tested

commit bdc9075
Author: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>
Date:   Thu Aug 24 16:47:25 2023 +0200

    Update check.yml (#78)

    * Update check.yml

    * Update check.yml

commit 6894904
Author: Juan Ignacio Rios <54085674+JuaniRios@users.noreply.github.com>
Date:   Wed Aug 23 14:17:19 2023 +0100

    Feature/plmc 242 implement correct duration of vesting (#70)

    * wip

    * feat(244): linear increase of duration based on vesting

    * Update pallets/funding/src/types.rs

    Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

    * feat(242): small changes from Leonardo's feedback

    * feat(242): change week to day conversion on config type

    * chore(242): fmt

    * feat(242): small optimization

    ---------

    Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

commit 8057e2e
Author: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>
Date:   Wed Aug 23 11:38:43 2023 +0200

    Update check.yml (#76)

commit b4579cc
Author: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>
Date:   Wed Aug 23 10:01:42 2023 +0200

    feat: update the CI to use paritytech/ci-linux:production (#73)

    * feat: update the CI to use paritytech/ci-linux:production

    * ci: execute fmt as a fail fast job

    * fmt: format to test the CI

    * feat: remove the check job

* feat: for testing purposes let's assume 1 USDT = 1USD

wip

wip: align TestBid creation

wip: switch to stable compiler

test: check the remainder

Update rust-toolchain.toml

Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

chore(244): move dep to workspace

wip: check the ct amount

feat: restore assert_matches macro

test: add the remainder round from excel

test: add more dbg outputs

refactor: split the fees calculation login in several fn

test: cleanup debug artefacts

feat: calculate the CT amount in CT directly

fix: use the Y from the KH

feat: just return the total_fee_weight

doc: specify the denomination of the pot

test: restore the assert_matches macro

git merge --squash -Xours origin/main

Squashed commit of the following:

commit a71eff7
Author: Juan Ignacio Rios <juani.rios.99@gmail.com>
Date:   Mon Aug 14 16:20:48 2023 +0200

    feat(243): Remove T::StorageItemId and replace it with hardcoded u32

commit 368abd9
Author: Juan Ignacio Rios <juani.rios.99@gmail.com>
Date:   Mon Aug 14 16:20:48 2023 +0200

    feat(249): Remove Option from Multipliers

    feat(249): Option no longer required for multipliers

    fix(243): rebase error

    chore(243): add import

    feat(245): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual release implemented and tested

    feat(247): automatic release implemented and tested

    feat(247): automatic release implemented and tested

    feat(248): manual release implemented and tested

    feat(248): automatic release implemented and tested

    wip

    feat(242): small optimization

    chore(242): fmt

    feat(242): change week to day conversion on config type

    feat(242): small changes from Leonardo's feedback

    Update pallets/funding/src/types.rs

    Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

    feat(244): linear increase of duration based on vesting

    wip

commit e576cdc
Author: Juan Ignacio Rios <54085674+JuaniRios@users.noreply.github.com>
Date:   Fri Aug 25 10:39:03 2023 +0100

    fix(243): rebase error (#72)

    chore(243): add import

    feat(245): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual and automatic release of PLMC and funding assets implemented and tested

    feat(247): manual release implemented and tested

    feat(247): automatic release implemented and tested

    feat(247): automatic release implemented and tested

    feat(248): manual release implemented and tested

    feat(248): automatic release implemented and tested

commit bdc9075
Author: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>
Date:   Thu Aug 24 16:47:25 2023 +0200

    Update check.yml (#78)

    * Update check.yml

    * Update check.yml

commit 6894904
Author: Juan Ignacio Rios <54085674+JuaniRios@users.noreply.github.com>
Date:   Wed Aug 23 14:17:19 2023 +0100

    Feature/plmc 242 implement correct duration of vesting (#70)

    * wip

    * feat(244): linear increase of duration based on vesting

    * Update pallets/funding/src/types.rs

    Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

    * feat(242): small changes from Leonardo's feedback

    * feat(242): change week to day conversion on config type

    * chore(242): fmt

    * feat(242): small optimization

    ---------

    Co-authored-by: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>

commit 8057e2e
Author: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>
Date:   Wed Aug 23 11:38:43 2023 +0200

    Update check.yml (#76)

commit b4579cc
Author: Leonardo Razovic <4128940+lrazovic@users.noreply.github.com>
Date:   Wed Aug 23 10:01:42 2023 +0200

    feat: update the CI to use paritytech/ci-linux:production (#73)

    * feat: update the CI to use paritytech/ci-linux:production

    * ci: execute fmt as a fail fast job

    * fmt: format to test the CI

    * feat: remove the check job

* feat(239): add remark to a skipped user

feat(239): add comments to `generate_evaluator_rewards_info` function

fmt

---------

Co-authored-by: Juan Ignacio Rios <juani.rios.99@gmail.com>
Co-authored-by: Juan Ignacio Rios <54085674+JuaniRios@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 30, 2023
1 parent a71eff7 commit 3b8dd40
Show file tree
Hide file tree
Showing 4 changed files with 651 additions and 96 deletions.
128 changes: 79 additions & 49 deletions pallets/funding/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use frame_support::{
};
use sp_arithmetic::{
traits::{CheckedDiv, CheckedSub, Zero},
Perquintill,
Percent, Perquintill,
};
use sp_runtime::traits::Convert;
use sp_std::marker::PhantomData;
Expand Down Expand Up @@ -1249,7 +1249,6 @@ impl<T: Config> Pallet<T> {
) -> Result<(), DispatchError> {
// * Get variables *
let project_details = ProjectsDetails::<T>::get(project_id).ok_or(Error::<T>::ProjectInfoNotFound)?;
let ct_price = project_details.weighted_average_price.ok_or(Error::<T>::ImpossibleState)?;
let reward_info =
if let EvaluatorsOutcome::Rewarded(info) = project_details.evaluation_round_info.evaluators_outcome {
info
Expand All @@ -1273,16 +1272,11 @@ impl<T: Config> Pallet<T> {
evaluation.late_usd_amount.saturating_add(evaluation.early_usd_amount),
reward_info.normal_evaluator_total_bonded_usd,
);
let total_reward_amount_usd = (early_reward_weight * reward_info.early_evaluator_reward_pot_usd)
.saturating_add(normal_reward_weight * reward_info.normal_evaluator_reward_pot_usd);
let reward_amount_ct: BalanceOf<T> = ct_price
.reciprocal()
.ok_or(Error::<T>::BadMath)?
.checked_mul_int(total_reward_amount_usd)
.ok_or(Error::<T>::BadMath)?;

let early_evaluators_rewards = early_reward_weight * reward_info.early_evaluator_reward_pot;
let normal_evaluators_rewards = normal_reward_weight * reward_info.normal_evaluator_reward_pot;
let total_reward_amount = early_evaluators_rewards.saturating_add(normal_evaluators_rewards);
// * Update storage *
T::ContributionTokenCurrency::mint_into(project_id, &evaluation.evaluator, reward_amount_ct)?;
T::ContributionTokenCurrency::mint_into(project_id, &evaluation.evaluator, total_reward_amount)?;
evaluation.rewarded_or_slashed = true;
Evaluations::<T>::insert((project_id, evaluator.clone(), evaluation_id), evaluation);

Expand All @@ -1291,7 +1285,7 @@ impl<T: Config> Pallet<T> {
project_id,
evaluator: evaluator.clone(),
id: evaluation_id,
amount: reward_amount_ct,
amount: total_reward_amount,
caller,
});

Expand Down Expand Up @@ -2090,11 +2084,6 @@ impl<T: Config> Pallet<T> {
FixedU128::saturating_from_rational(contribution_amount, weighted_average_price)
}

pub fn add_decimals_to_number(number: BalanceOf<T>, decimals: u8) -> BalanceOf<T> {
let zeroes: BalanceOf<T> = BalanceOf::<T>::from(10u64).saturating_pow(decimals.into());
number.saturating_mul(zeroes)
}

pub fn try_plmc_participation_lock(
who: &T::AccountId,
project_id: T::ProjectIdentifier,
Expand Down Expand Up @@ -2140,45 +2129,81 @@ impl<T: Config> Pallet<T> {
Ok(())
}

pub fn calculate_fees(project_id: T::ProjectIdentifier) -> Result<BalanceOf<T>, DispatchError> {
let funding_reached =
ProjectsDetails::<T>::get(project_id).ok_or(Error::<T>::ProjectNotFound)?.funding_amount_reached;
/// Calculate the total fees based on the funding reached.
pub fn calculate_fees(funding_reached: BalanceOf<T>) -> Perquintill {
let total_fee = Self::compute_total_fee_from_brackets(funding_reached);
Perquintill::from_rational(total_fee, funding_reached)
}

/// Computes the total fee from all defined fee brackets.
fn compute_total_fee_from_brackets(funding_reached: BalanceOf<T>) -> BalanceOf<T> {
let mut remaining_for_fee = funding_reached;

Ok(T::FeeBrackets::get()
T::FeeBrackets::get()
.into_iter()
.map(|(fee, limit)| {
let try_operation = remaining_for_fee.checked_sub(&limit);
if let Some(remaining_amount) = try_operation {
remaining_for_fee = remaining_amount;
fee * limit
} else {
let temp = remaining_for_fee;
remaining_for_fee = BalanceOf::<T>::zero();
fee * temp
}
})
.fold(BalanceOf::<T>::zero(), |acc, fee| acc.saturating_add(fee)))
.map(|(fee, limit)| Self::compute_fee_for_bracket(&mut remaining_for_fee, fee, limit))
.fold(BalanceOf::<T>::zero(), |acc, fee| acc.saturating_add(fee))
}

/// Calculate the fee for a particular bracket.
fn compute_fee_for_bracket(
remaining_for_fee: &mut BalanceOf<T>,
fee: Percent,
limit: BalanceOf<T>,
) -> BalanceOf<T> {
if let Some(remaining_amount) = remaining_for_fee.checked_sub(&limit) {
*remaining_for_fee = remaining_amount;
fee * limit
} else {
let fee_for_this_bracket = fee * *remaining_for_fee;
*remaining_for_fee = BalanceOf::<T>::zero();
fee_for_this_bracket
}
}

/// Generate and return evaluator rewards based on a project's funding status.
///
/// The function calculates rewards based on several metrics: funding achieved,
/// total allocations, and issuer fees. It also differentiates between early and
/// normal evaluators for reward distribution.
///
/// Note: Consider refactoring the `RewardInfo` struct to make it more generic and
/// reusable, not just for evaluator rewards.
pub fn generate_evaluator_rewards_info(
project_id: <T as Config>::ProjectIdentifier,
) -> Result<RewardInfoOf<T>, DispatchError> {
// Fetching the necessary data for a specific project.
let project_details = ProjectsDetails::<T>::get(project_id).ok_or(Error::<T>::ProjectNotFound)?;
let project_metadata = ProjectsMetadata::<T>::get(project_id).ok_or(Error::<T>::ProjectNotFound)?;
let evaluations = Evaluations::<T>::iter_prefix((project_id,)).collect::<Vec<_>>();

let target_funding = project_details.fundraising_target;
let funding_reached = project_details.funding_amount_reached;

// This is the "Y" variable from the knowledge hub
let percentage_of_target_funding = Perquintill::from_rational(funding_reached, target_funding);

let fees = Self::calculate_fees(project_id)?;
let evaluator_fees = percentage_of_target_funding * (Perquintill::from_percent(30) * fees);

let early_evaluator_reward_pot_usd = Perquintill::from_percent(20) * evaluator_fees;
let normal_evaluator_reward_pot_usd = Perquintill::from_percent(80) * evaluator_fees;

// Determine how much funding has been achieved.
let funding_amount_reached = project_details.funding_amount_reached;
let fundraising_target = project_details.fundraising_target;
let total_issuer_fees = Self::calculate_fees(funding_amount_reached);

// Calculate the number of tokens sold for the project.
let token_sold = project_metadata
.total_allocation_size
.checked_sub(&project_details.remaining_contribution_tokens)
// Ensure safety by providing a default in case of unexpected situations.
.unwrap_or(project_metadata.total_allocation_size);
let total_fee_allocation = total_issuer_fees * token_sold;

// Calculate the percentage of target funding based on available documentation.
let percentage_of_target_funding = Perquintill::from_rational(funding_amount_reached, fundraising_target);

// Calculate rewards.
let evaluator_rewards = percentage_of_target_funding * Perquintill::from_percent(30) * total_fee_allocation;
// Placeholder allocations (intended for future use).
let _liquidity_pool = Perquintill::from_percent(50) * total_fee_allocation;
let _long_term_holder_bonus = _liquidity_pool.saturating_sub(evaluator_rewards);

// Distribute rewards between early and normal evaluators.
let early_evaluator_reward_pot = Perquintill::from_percent(20) * evaluator_rewards;
let normal_evaluator_reward_pot = Perquintill::from_percent(80) * evaluator_rewards;

// Sum up the total bonded USD amounts for both early and late evaluators.
let early_evaluator_total_bonded_usd =
evaluations.iter().fold(BalanceOf::<T>::zero(), |acc, ((_evaluator, _id), evaluation)| {
acc.saturating_add(evaluation.early_usd_amount)
Expand All @@ -2187,14 +2212,19 @@ impl<T: Config> Pallet<T> {
evaluations.iter().fold(BalanceOf::<T>::zero(), |acc, ((_evaluator, _id), evaluation)| {
acc.saturating_add(evaluation.late_usd_amount)
});

let normal_evaluator_total_bonded_usd =
early_evaluator_total_bonded_usd.saturating_add(late_evaluator_total_bonded_usd);
Ok(RewardInfo {
early_evaluator_reward_pot_usd,
normal_evaluator_reward_pot_usd,

// Construct the reward information object.
let reward_info = RewardInfo {
early_evaluator_reward_pot,
normal_evaluator_reward_pot,
early_evaluator_total_bonded_usd,
normal_evaluator_total_bonded_usd,
})
};

Ok(reward_info)
}

pub fn make_project_funding_successful(
Expand Down
2 changes: 1 addition & 1 deletion pallets/funding/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ parameter_types! {
pub PriceMap: BTreeMap<AssetId, FixedU128> = BTreeMap::from_iter(vec![
(0u32, FixedU128::from_float(69f64)), // DOT
(420u32, FixedU128::from_float(0.97f64)), // USDC
(1984u32, FixedU128::from_float(0.95f64)), // USDT
(1984u32, FixedU128::from_float(1.0f64)), // USDT
(2069u32, FixedU128::from_float(8.4f64)), // PLMC
]);
pub FeeBrackets: Vec<(Percent, Balance)> = vec![
Expand Down
Loading

0 comments on commit 3b8dd40

Please sign in to comment.