Skip to content

Commit

Permalink
earning precompile
Browse files Browse the repository at this point in the history
  • Loading branch information
wangjj9219 committed Jul 8, 2024
1 parent 33c1601 commit ef4aadd
Show file tree
Hide file tree
Showing 10 changed files with 899 additions and 74 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions modules/earning/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ sp-std = { workspace = true }

orml-traits = { workspace = true }
primitives = { workspace = true }
module-support = { workspace = true }

[dev-dependencies]
sp-io = { workspace = true, features = ["std"] }
Expand All @@ -32,6 +33,7 @@ std = [
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"module-support/std",
]
try-runtime = [
"frame-support/try-runtime",
Expand Down
199 changes: 132 additions & 67 deletions modules/earning/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use frame_support::{
traits::{Currency, ExistenceRequirement, LockIdentifier, LockableCurrency, OnUnbalanced, WithdrawReasons},
};
use frame_system::pallet_prelude::*;
use module_support::EarningManager;
use orml_traits::{define_parameters, parameters::ParameterStore, Handler};
use primitives::{
bonding::{self, BondingController},
Expand Down Expand Up @@ -138,16 +139,7 @@ pub mod module {
pub fn bond(origin: OriginFor<T>, #[pallet::compact] amount: Balance) -> DispatchResult {
let who = ensure_signed(origin)?;

let change = <Self as BondingController>::bond(&who, amount)?;

if let Some(change) = change {
T::OnBonded::handle(&(who.clone(), change.change))?;
Self::deposit_event(Event::Bonded {
who,
amount: change.change,
});
}
Ok(())
Self::do_bond(&who, amount)
}

/// Start unbonding tokens up to `amount`.
Expand All @@ -158,18 +150,7 @@ pub mod module {
pub fn unbond(origin: OriginFor<T>, #[pallet::compact] amount: Balance) -> DispatchResult {
let who = ensure_signed(origin)?;

let unbond_at = frame_system::Pallet::<T>::block_number().saturating_add(T::UnbondingPeriod::get());
let change = <Self as BondingController>::unbond(&who, amount, unbond_at)?;

if let Some(change) = change {
T::OnUnbonded::handle(&(who.clone(), change.change))?;
Self::deposit_event(Event::Unbonded {
who,
amount: change.change,
});
}

Ok(())
Self::do_unbond(&who, amount)
}

/// Unbond up to `amount` tokens instantly by paying a `InstantUnstakeFee` fee.
Expand All @@ -180,29 +161,7 @@ pub mod module {
pub fn unbond_instant(origin: OriginFor<T>, #[pallet::compact] amount: Balance) -> DispatchResult {
let who = ensure_signed(origin)?;

let fee_ratio = T::ParameterStore::get(InstantUnstakeFee).ok_or(Error::<T>::NotAllowed)?;

let change = <Self as BondingController>::unbond_instant(&who, amount)?;

if let Some(change) = change {
let amount = change.change;
let fee = fee_ratio.mul_ceil(amount);
let final_amount = amount.saturating_sub(fee);

let unbalance =
T::Currency::withdraw(&who, fee, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive)?;
T::OnUnstakeFee::on_unbalanced(unbalance);

// remove all shares of the change amount.
T::OnUnbonded::handle(&(who.clone(), amount))?;
Self::deposit_event(Event::InstantUnbonded {
who,
amount: final_amount,
fee,
});
}

Ok(())
Self::do_unbond_instant(&who, amount)
}

/// Rebond up to `amount` tokens from unbonding period.
Expand All @@ -213,17 +172,7 @@ pub mod module {
pub fn rebond(origin: OriginFor<T>, #[pallet::compact] amount: Balance) -> DispatchResult {
let who = ensure_signed(origin)?;

let change = <Self as BondingController>::rebond(&who, amount)?;

if let Some(change) = change {
T::OnBonded::handle(&(who.clone(), change.change))?;
Self::deposit_event(Event::Rebonded {
who,
amount: change.change,
});
}

Ok(())
Self::do_rebond(&who, amount)
}

/// Withdraw all unbonded tokens.
Expand All @@ -232,22 +181,93 @@ pub mod module {
pub fn withdraw_unbonded(origin: OriginFor<T>) -> DispatchResult {
let who = ensure_signed(origin)?;

let change =
<Self as BondingController>::withdraw_unbonded(&who, frame_system::Pallet::<T>::block_number())?;
Self::do_withdraw_unbonded(&who)
}
}
}

if let Some(change) = change {
Self::deposit_event(Event::Withdrawn {
who,
amount: change.change,
});
}
impl<T: Config> Pallet<T> {
fn do_bond(who: &T::AccountId, amount: Balance) -> DispatchResult {
let change = <Self as BondingController>::bond(who, amount)?;

Ok(())
if let Some(change) = change {
T::OnBonded::handle(&(who.clone(), change.change))?;
Self::deposit_event(Event::Bonded {
who: who.clone(),
amount: change.change,
});
}
Ok(())
}
}

impl<T: Config> Pallet<T> {}
fn do_unbond(who: &T::AccountId, amount: Balance) -> DispatchResult {
let unbond_at = frame_system::Pallet::<T>::block_number().saturating_add(T::UnbondingPeriod::get());
let change = <Self as BondingController>::unbond(who, amount, unbond_at)?;

if let Some(change) = change {
T::OnUnbonded::handle(&(who.clone(), change.change))?;
Self::deposit_event(Event::Unbonded {
who: who.clone(),
amount: change.change,
});
}

Ok(())
}

fn do_unbond_instant(who: &T::AccountId, amount: Balance) -> DispatchResult {
let fee_ratio = T::ParameterStore::get(InstantUnstakeFee).ok_or(Error::<T>::NotAllowed)?;

let change = <Self as BondingController>::unbond_instant(who, amount)?;

if let Some(change) = change {
let amount = change.change;
let fee = fee_ratio.mul_ceil(amount);
let final_amount = amount.saturating_sub(fee);

let unbalance =
T::Currency::withdraw(who, fee, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive)?;
T::OnUnstakeFee::on_unbalanced(unbalance);

// remove all shares of the change amount.
T::OnUnbonded::handle(&(who.clone(), amount))?;
Self::deposit_event(Event::InstantUnbonded {
who: who.clone(),
amount: final_amount,
fee,
});
}

Ok(())
}

fn do_rebond(who: &T::AccountId, amount: Balance) -> DispatchResult {
let change = <Self as BondingController>::rebond(who, amount)?;

if let Some(change) = change {
T::OnBonded::handle(&(who.clone(), change.change))?;
Self::deposit_event(Event::Rebonded {
who: who.clone(),
amount: change.change,
});
}

Ok(())
}

fn do_withdraw_unbonded(who: &T::AccountId) -> DispatchResult {
let change = <Self as BondingController>::withdraw_unbonded(who, frame_system::Pallet::<T>::block_number())?;

if let Some(change) = change {
Self::deposit_event(Event::Withdrawn {
who: who.clone(),
amount: change.change,
});
}

Ok(())
}
}

impl<T: Config> BondingController for Pallet<T> {
type MinBond = T::MinBond;
Expand Down Expand Up @@ -279,3 +299,48 @@ impl<T: Config> BondingController for Pallet<T> {
}
}
}

impl<T: Config> EarningManager<T::AccountId, Balance, BondingLedgerOf<T>> for Pallet<T> {
type Moment = BlockNumberFor<T>;
type FeeRatio = Permill;

fn bond(who: T::AccountId, amount: Balance) -> DispatchResult {
Self::do_bond(&who, amount)
}

fn unbond(who: T::AccountId, amount: Balance) -> DispatchResult {
Self::do_unbond(&who, amount)
}

fn unbond_instant(who: T::AccountId, amount: Balance) -> DispatchResult {
Self::do_unbond_instant(&who, amount)
}

fn rebond(who: T::AccountId, amount: Balance) -> DispatchResult {
Self::do_rebond(&who, amount)
}

fn withdraw_unbonded(who: T::AccountId) -> DispatchResult {
Self::do_withdraw_unbonded(&who)
}

fn get_bonding_ledger(who: T::AccountId) -> BondingLedgerOf<T> {
Self::ledger(who).unwrap_or_default()
}

fn get_instant_unstake_fee() -> Permill {
T::ParameterStore::get(InstantUnstakeFee).unwrap_or_default()
}

fn get_min_bond() -> Balance {
T::MinBond::get()
}

fn get_unbonding_period() -> BlockNumberFor<T> {
T::UnbondingPeriod::get()
}

fn get_max_unbonding_chunks() -> u32 {
T::MaxUnbondingChunks::get()
}
}
34 changes: 34 additions & 0 deletions modules/support/src/earning.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// This file is part of Acala.

// Copyright (C) 2020-2024 Acala Foundation.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use sp_runtime::DispatchResult;

pub trait EarningManager<AccountId, Balance, BondingLedger> {
type Moment;
type FeeRatio;
fn bond(who: AccountId, amount: Balance) -> DispatchResult;
fn unbond(who: AccountId, amount: Balance) -> DispatchResult;
fn unbond_instant(who: AccountId, amount: Balance) -> DispatchResult;
fn rebond(who: AccountId, amount: Balance) -> DispatchResult;
fn withdraw_unbonded(who: AccountId) -> DispatchResult;
fn get_bonding_ledger(who: AccountId) -> BondingLedger;
fn get_min_bond() -> Balance;
fn get_unbonding_period() -> Self::Moment;
fn get_max_unbonding_chunks() -> u32;
fn get_instant_unstake_fee() -> Self::FeeRatio;
}
2 changes: 2 additions & 0 deletions modules/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use xcm::prelude::*;

pub mod bounded;
pub mod dex;
pub mod earning;
pub mod evm;
pub mod homa;
pub mod honzon;
Expand All @@ -42,6 +43,7 @@ pub mod stable_asset;

pub use crate::bounded::*;
pub use crate::dex::*;
pub use crate::earning::*;
pub use crate::evm::*;
pub use crate::homa::*;
pub use crate::honzon::*;
Expand Down
10 changes: 5 additions & 5 deletions primitives/src/bonding/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ use frame_support::pallet_prelude::*;
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)]
pub struct UnlockChunk<Moment> {
/// Amount of funds to be unlocked.
value: Balance,
pub value: Balance,
/// Era number at which point it'll be unlocked.
unlock_at: Moment,
pub unlock_at: Moment,
}

/// The ledger of a (bonded) account.
Expand All @@ -45,13 +45,13 @@ where
/// The total amount of the account's balance that we are currently
/// accounting for. It's just `active` plus all the `unlocking`
/// balances.
total: Balance,
pub total: Balance,
/// The total amount of the account's balance that will be at stake in
/// any forthcoming rounds.
active: Balance,
pub active: Balance,
/// Any balance that is becoming free, which may eventually be
/// transferred out of the account.
unlocking: BoundedVec<UnlockChunk<Moment>, MaxUnlockingChunks>,
pub unlocking: BoundedVec<UnlockChunk<Moment>, MaxUnlockingChunks>,

_phantom: PhantomData<MinBond>,
}
Expand Down
Loading

0 comments on commit ef4aadd

Please sign in to comment.