#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::{pallet_prelude::*, traits::tokens::fungible};
use sp_runtime::{
traits::{CheckedDiv, CheckedMul},
FixedPointNumber, RuntimeDebug,
};
use sp_std::prelude::*;
pub use xcm::v4::{opaque::Xcm, Assets, Location, QueryId, SendError, SendResult, SendXcm, XcmHash};
pub mod credentials;
pub trait ReleaseSchedule<AccountId, Reason> {
type Moment;
type Currency: fungible::InspectHold<AccountId>
+ fungible::MutateHold<AccountId>
+ fungible::BalancedHold<AccountId>;
fn vesting_balance(
who: &AccountId,
reason: Reason,
) -> Option<<Self::Currency as fungible::Inspect<AccountId>>::Balance>;
fn total_scheduled_amount(
who: &AccountId,
reason: Reason,
) -> Option<<Self::Currency as fungible::Inspect<AccountId>>::Balance>;
fn vest(
who: AccountId,
reason: Reason,
) -> Result<<Self::Currency as fungible::Inspect<AccountId>>::Balance, DispatchError>;
fn add_release_schedule(
who: &AccountId,
locked: <Self::Currency as fungible::Inspect<AccountId>>::Balance,
per_block: <Self::Currency as fungible::Inspect<AccountId>>::Balance,
starting_block: Self::Moment,
reason: Reason,
) -> DispatchResult;
fn set_release_schedule(
who: &AccountId,
locked: <Self::Currency as fungible::Inspect<AccountId>>::Balance,
per_block: <Self::Currency as fungible::Inspect<AccountId>>::Balance,
starting_block: Self::Moment,
reason: Reason,
) -> DispatchResult;
fn can_add_release_schedule(
who: &AccountId,
locked: <Self::Currency as fungible::Inspect<AccountId>>::Balance,
per_block: <Self::Currency as fungible::Inspect<AccountId>>::Balance,
starting_block: Self::Moment,
reason: Reason,
) -> DispatchResult;
fn remove_vesting_schedule(who: &AccountId, schedule_index: u32, reason: Reason) -> DispatchResult;
fn remove_all_vesting_schedules(who: &AccountId, reason: Reason) -> DispatchResult;
}
pub mod migration_types {
#[allow(clippy::wildcard_imports)]
use super::*;
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct MigrationOrigin {
pub user: Location,
pub id: u32,
pub participation_type: ParticipationType,
}
impl PartialOrd for MigrationOrigin {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MigrationOrigin {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
if self.participation_type == other.participation_type {
self.id.cmp(&other.id)
} else {
self.participation_type.cmp(&other.participation_type)
}
}
}
#[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub enum ParticipationType {
Evaluation,
Bid,
Contribution,
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct MigrationInfo {
pub contribution_token_amount: u128,
pub vesting_time: u64,
}
impl From<(u128, u64)> for MigrationInfo {
fn from((contribution_token_amount, vesting_time): (u128, u64)) -> Self {
Self { contribution_token_amount, vesting_time }
}
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub enum MigrationStatus {
NotStarted,
Sent(QueryId),
Confirmed,
Failed,
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct Migration {
pub origin: MigrationOrigin,
pub info: MigrationInfo,
}
impl Migration {
pub fn new(origin: MigrationOrigin, info: MigrationInfo) -> Self {
Self { origin, info }
}
}
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, Default)]
pub struct Migrations(Vec<Migration>);
impl FromIterator<Migration> for Migrations {
fn from_iter<T: IntoIterator<Item = Migration>>(iter: T) -> Self {
Migrations::from(iter.into_iter().collect::<Vec<_>>())
}
}
impl Migrations {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn inner(self) -> Vec<Migration> {
self.0
}
pub fn push(&mut self, migration: Migration) {
self.0.push(migration)
}
pub fn from(migrations: Vec<Migration>) -> Self {
Self(migrations)
}
pub fn contains(&self, migration: &Migration) -> bool {
self.0.contains(migration)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn origins(&self) -> Vec<MigrationOrigin> {
self.0.iter().map(|migration| migration.origin.clone()).collect()
}
pub fn infos(&self) -> Vec<MigrationInfo> {
self.0.iter().map(|migration| migration.info.clone()).collect()
}
pub fn total_ct_amount(&self) -> u128 {
self.0.iter().map(|migration| migration.info.contribution_token_amount).sum()
}
pub fn biggest_vesting_time(&self) -> u64 {
self.0.iter().map(|migration| migration.info.vesting_time).max().unwrap_or(0)
}
}
}
pub const USD_DECIMALS: u8 = 6;
pub const USD_UNIT: u128 = 10u128.pow(USD_DECIMALS as u32);
pub const PLMC_DECIMALS: u8 = 10;
pub const PLMC_FOREIGN_ID: u32 = 3344;
pub trait ProvideAssetPrice {
type AssetId;
type Price: FixedPointNumber;
fn get_price(asset_id: Self::AssetId) -> Option<Self::Price>;
fn calculate_decimals_aware_price(
original_price: Self::Price,
usd_decimals: u8,
asset_decimals: u8,
) -> Option<Self::Price> {
let usd_unit = 10u128.checked_pow(usd_decimals.into())?;
let usd_price_with_decimals = original_price.checked_mul_int(usd_unit)?;
let asset_unit = 10u128.checked_pow(asset_decimals.into())?;
Self::Price::checked_from_rational(usd_price_with_decimals, asset_unit)
}
fn convert_back_to_normal_price(
decimals_aware_price: Self::Price,
usd_decimals: u8,
asset_decimals: u8,
) -> Option<Self::Price> {
let abs_diff: u32 = asset_decimals.abs_diff(usd_decimals).into();
let abs_diff_unit = 10u128.checked_pow(abs_diff)?;
let abs_diff_fixed = Self::Price::checked_from_rational(abs_diff_unit, 1)?;
if usd_decimals > asset_decimals {
decimals_aware_price.checked_div(&abs_diff_fixed)
} else {
decimals_aware_price.checked_mul(&abs_diff_fixed)
}
}
fn get_decimals_aware_price(asset_id: Self::AssetId, usd_decimals: u8, asset_decimals: u8) -> Option<Self::Price> {
let original_price = Self::get_price(asset_id)?;
Self::calculate_decimals_aware_price(original_price, usd_decimals, asset_decimals)
}
}