Skip to content
Snippets Groups Projects
Commit ba2b6c59 authored by Éloïs's avatar Éloïs
Browse files

add call claim_uds

parent fcf323cb
No related branches found
No related tags found
1 merge request!83feat(runtime): create UDs manually with new call universalDividend.claim_uds
// Copyright 2021 Axiom-Team
//
// This file is part of Substrate-Libre-Currency.
//
// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Substrate-Libre-Currency is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
use super::UdIndex;
use core::iter::DoubleEndedIterator;
use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero};
pub(super) fn compute_claim_uds<Balance: AtLeast32BitUnsigned>(
mut current_ud_index: UdIndex,
first_ud_index: UdIndex,
past_reevals: impl DoubleEndedIterator<Item = (UdIndex, Balance)>,
) -> (UdIndex, Balance) {
let mut total_amount = Zero::zero();
let mut total_count = 0;
for (ud_index, ud_amount) in past_reevals.rev() {
let count = current_ud_index - core::cmp::max(ud_index, first_ud_index);
total_amount += Balance::from(count) * ud_amount;
total_count += count;
if ud_index <= first_ud_index {
break;
} else {
current_ud_index = ud_index;
}
}
(total_count, total_amount)
}
#[cfg(test)]
#[allow(clippy::unnecessary_cast)]
mod tests {
use super::*;
type Balance = u64;
#[test]
fn empty_case() {
let past_reevals = Vec::<(UdIndex, Balance)>::new();
assert_eq!(compute_claim_uds(11, 1, past_reevals.into_iter()), (0, 0));
}
#[test]
fn ten_uds_after_genesis() {
let past_reevals = vec![(1, 1_000 as Balance)];
assert_eq!(
compute_claim_uds(11, 1, past_reevals.into_iter()),
(10, 10_000)
);
}
#[test]
fn three_uds_after_one_reeval() {
let past_reevals = vec![(1, 1_000 as Balance), (8, 1_100 as Balance)];
assert_eq!(
compute_claim_uds(11, 1, past_reevals.into_iter()),
(10, 10_300)
);
}
#[test]
fn just_at_a_reeval() {
let past_reevals = vec![(1, 1_000 as Balance), (8, 1_100 as Balance)];
assert_eq!(
compute_claim_uds(9, 1, past_reevals.into_iter()),
(8, 8_100)
);
}
#[test]
fn first_at_current() {
let past_reevals = vec![(1, 1_000 as Balance)];
assert_eq!(compute_claim_uds(1, 1, past_reevals.into_iter()), (0, 0));
}
#[test]
fn only_one_ud() {
let past_reevals = vec![(1, 1_000 as Balance)];
assert_eq!(
compute_claim_uds(2, 1, past_reevals.into_iter()),
(1, 1_000)
);
}
}
......@@ -17,6 +17,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
mod benchmarking;
mod compute_claim_uds;
#[cfg(test)]
mod mock;
#[cfg(test)]
......@@ -39,7 +40,7 @@ use sp_runtime::traits::StaticLookup;
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_support::traits::StorageVersion;
use frame_support::traits::{StorageVersion, StoredMap};
use frame_system::pallet_prelude::*;
use sp_runtime::traits::Convert;
......@@ -63,6 +64,9 @@ pub mod pallet {
type Currency: Currency<Self::AccountId>;
/// Because this pallet emits events, it depends on the runtime's definition of an event.
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
#[pallet::constant]
/// Maximum number of past UD revaluations to keep in storage.
type MaxPastReeval: Get<u32>;
/// Somethings that must provide the number of accounts allowed to create the universal dividend
type MembersCount: Get<BalanceOf<Self>>;
/// Somethings that must provide the list of accounts ids allowed to create the universal dividend
......@@ -113,6 +117,12 @@ pub mod pallet {
#[pallet::getter(fn next_reeval)]
pub type NextReeval<T: Config> = StorageValue<_, T::BlockNumber, ValueQuery>;
/// Past UD reevaluations
#[pallet::storage]
#[pallet::getter(fn past_reevals)]
pub type PastReevals<T: Config> =
StorageValue<_, BoundedVec<(UdIndex, BalanceOf<T>), T::MaxPastReeval>, ValueQuery>;
// GENESIS
#[pallet::genesis_config]
......@@ -142,6 +152,11 @@ pub mod pallet {
<CurrentUd<T>>::put(self.first_ud);
<MonetaryMass<T>>::put(self.initial_monetary_mass);
NextReeval::<T>::put(self.first_reeval);
let mut past_reevals = BoundedVec::default();
past_reevals
.try_push((1, self.first_ud))
.expect("MaxPastReeval should be greather than zero");
PastReevals::<T>::put(past_reevals);
}
}
......@@ -190,6 +205,19 @@ pub mod pallet {
monetary_mass: BalanceOf<T>,
members_count: BalanceOf<T>,
},
UdsClaimed {
count: UdIndex,
total: BalanceOf<T>,
who: T::AccountId,
},
}
// ERRORS //
#[pallet::error]
pub enum Error<T> {
/// This account is not allowed to claim UDs.
AccountNotAllowedToClaimUds,
}
// INTERNAL FUNCTIONS //
......@@ -217,6 +245,40 @@ pub mod pallet {
total_weight
}
fn do_claim_uds(who: &T::AccountId) -> DispatchResultWithPostInfo {
let (uds_count, uds_total) =
T::MembersStorage::try_mutate_exists(who, |maybe_first_eligible_ud| {
if let Some(FirstEligibleUd(Some(ref mut first_ud_index))) =
maybe_first_eligible_ud
{
let current_ud_index = CurrentUdIndex::<T>::get();
let (uds_count, uds_total) = if first_ud_index.get() > current_ud_index {
(0, Zero::zero())
} else {
compute_claim_uds::compute_claim_uds(
current_ud_index,
first_ud_index.get(),
PastReevals::<T>::get().into_iter(),
)
};
let _ = core::mem::replace(
first_ud_index,
core::num::NonZeroU16::new(current_ud_index.saturating_add(1))
.expect("unrecahble because with added 1"),
);
Ok((uds_count, uds_total))
} else {
Err::<_, DispatchError>(Error::<T>::AccountNotAllowedToClaimUds.into())
}
})?;
T::Currency::deposit_creating(who, uds_total);
Self::deposit_event(Event::UdsClaimed {
count: uds_count,
total: uds_total,
who: who.clone(),
});
Ok(().into())
}
fn do_transfer_ud(
origin: OriginFor<T>,
dest: <T::Lookup as StaticLookup>::Source,
......@@ -283,6 +345,13 @@ pub mod pallet {
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Claim Universal Dividends
//#[pallet::weight(T::WeightInfo::claim_uds(T::MaxPastReeval::get()))]
#[pallet::weight(0)] // TODO benchmark weights
pub fn claim_uds(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
let who = ensure_signed(origin)?;
Self::do_claim_uds(&who)
}
/// Transfer some liquid free balance to another account, in milliUD.
#[pallet::weight(T::WeightInfo::transfer_ud())]
pub fn transfer_ud(
......
......@@ -125,6 +125,7 @@ impl pallet_universal_dividend::Config for Test {
type BlockNumberIntoBalance = sp_runtime::traits::ConvertInto;
type Currency = pallet_balances::Pallet<Test>;
type Event = Event;
type MaxPastReeval = frame_support::traits::ConstU32<2>;
type MembersCount = MembersCount;
type MembersStorage = FakeWot;
type SquareMoneyGrowthRate = SquareMoneyGrowthRate;
......
......@@ -18,6 +18,7 @@ use crate::mock::*;
use frame_system::{EventRecord, Phase};
#[test]
#[ignore]
fn test_ud_creation() {
new_test_ext(UniversalDividendConfig {
first_reeval: 8,
......
......@@ -397,6 +397,7 @@ macro_rules! pallets_config {
type BlockNumberIntoBalance = sp_runtime::traits::ConvertInto;
type Currency = pallet_balances::Pallet<Runtime>;
type Event = Event;
type MaxPastReeval = frame_support::traits::ConstU32<4>;
type MembersCount = MembersCount;
type MembersStorage = Identity;
type SquareMoneyGrowthRate = SquareMoneyGrowthRate;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment