Skip to content

Commit a03396c

Browse files
authored
Refine mining asset (paritytech#168)
* Do not need to exclude PCX in OnAssetChanged methods * Add referral reward split * Add GatewayInterface in mining/asset * Test asset mining reward * Add some docs
1 parent 7b918e6 commit a03396c

File tree

6 files changed

+244
-80
lines changed

6 files changed

+244
-80
lines changed

runtime/src/lib.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -753,14 +753,23 @@ impl xpallet_mining_staking::Trait for Runtime {
753753
type SessionDuration = SessionDuration;
754754
type SessionInterface = Self;
755755
type TreasuryAccount = SimpleTreasuryAccount;
756-
type AssetMining = ();
756+
type AssetMining = XMiningAsset;
757757
type DetermineRewardPotAccount =
758758
xpallet_mining_staking::SimpleValidatorRewardPotAccountDeterminer<Runtime>;
759759
}
760760

761+
pub struct DummyReferralGetter;
762+
impl xpallet_mining_asset::GatewayInterface<AccountId> for DummyReferralGetter {
763+
fn referral_of(_who: &AccountId) -> Option<AccountId> {
764+
// FIXME impl this in gateway
765+
None
766+
}
767+
}
768+
761769
impl xpallet_mining_asset::Trait for Runtime {
762770
type Event = Event;
763771
type StakingInterface = Self;
772+
type GatewayInterface = DummyReferralGetter;
764773
type TreasuryAccount = SimpleTreasuryAccount;
765774
type DetermineRewardPotAccount =
766775
xpallet_mining_asset::SimpleAssetRewardPotAccountDeterminer<Runtime>;
@@ -1038,10 +1047,9 @@ impl_runtime_apis! {
10381047
}
10391048

10401049
fn trustee_session_info(chain: Chain) -> Option<GenericTrusteeSessionInfo<AccountId>> {
1041-
let number = match XGatewayCommon::trustee_session_info_len(chain).checked_sub(1) {
1042-
Some(r) => r,
1043-
None => u32::max_value(),
1044-
};
1050+
let number = XGatewayCommon::trustee_session_info_len(chain)
1051+
.checked_sub(1)
1052+
.unwrap_or_else(u32::max_value);
10451053
XGatewayCommon::trustee_session_info_of(chain, number)
10461054
}
10471055

xpallets/mining/asset/src/impls.rs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use super::*;
22
use codec::Encode;
33
use sp_core::crypto::UncheckedFrom;
4-
use sp_runtime::traits::Hash;
5-
use sp_runtime::traits::Saturating;
4+
use sp_runtime::traits::{Hash, Saturating};
65
use xp_mining_common::{
76
generic_weight_factors, BaseMiningWeight, Claim, ComputeMiningWeight, WeightFactors, WeightType,
87
};
@@ -76,11 +75,20 @@ impl<T: Trait> ComputeMiningWeight<T::AccountId, T::BlockNumber> for Module<T> {
7675
}
7776
}
7877

78+
// ChainX now uses pallet_balances for native coin PCX, therefore we do not
79+
// have to exclude PCX asset in these OnAssetChanged methods:
80+
//
81+
// * `on_issue_pre`
82+
// * `on_issue_post`
83+
// * `on_move_pre`
84+
//
85+
// ```rust
86+
// if xpallet_protocol::PCX == *target {
87+
// return Ok(());
88+
// }
89+
// ```
7990
impl<T: Trait> xpallet_assets::OnAssetChanged<T::AccountId, BalanceOf<T>> for Module<T> {
8091
fn on_issue_pre(target: &AssetId, source: &T::AccountId) {
81-
if xpallet_protocol::PCX == *target {
82-
return;
83-
}
8492
let current_block = <frame_system::Module<T>>::block_number();
8593
Self::init_receiver_mining_ledger(source, target, current_block);
8694

@@ -92,9 +100,6 @@ impl<T: Trait> xpallet_assets::OnAssetChanged<T::AccountId, BalanceOf<T>> for Mo
92100
source: &T::AccountId,
93101
_value: BalanceOf<T>,
94102
) -> DispatchResult {
95-
if xpallet_protocol::PCX == *target {
96-
return Ok(());
97-
}
98103
Self::issue_deposit_reward(source, target)
99104
}
100105

@@ -106,9 +111,10 @@ impl<T: Trait> xpallet_assets::OnAssetChanged<T::AccountId, BalanceOf<T>> for Mo
106111
_: AssetType,
107112
_: BalanceOf<T>,
108113
) {
109-
if xpallet_protocol::PCX == *asset_id || from == to {
114+
if from == to {
110115
return;
111116
}
117+
112118
let current_block = <frame_system::Module<T>>::block_number();
113119
Self::init_receiver_mining_ledger(to, asset_id, current_block);
114120

@@ -123,15 +129,32 @@ impl<T: Trait> xpallet_assets::OnAssetChanged<T::AccountId, BalanceOf<T>> for Mo
123129
}
124130

125131
impl<T: Trait> Module<T> {
132+
/// Allocates the dividend to claimer and referral(treasury) accordingly.
133+
///
134+
/// Each asset miner can have a referral, which splits the 10% of
135+
/// of total asset mining dividend. The 10% split will be transferred
136+
/// to the treasury account if the claimer does not have a referral.
137+
///
138+
/// total_asset_miner_dividend
139+
/// ├──> referral(treasury) 10%
140+
/// └──> claimer 90%
126141
fn allocate_dividend(
142+
claimee_reward_pot: &T::AccountId,
127143
claimer: &T::AccountId,
128-
_claimee: &AssetId,
129-
_claimee_reward_pot: &T::AccountId,
130144
dividend: BalanceOf<T>,
131145
) -> Result<(), Error<T>> {
132-
// todo!("referral_or_treasury 10%, claimer 90%")
133-
// FIXME
134-
// let _ = xpallet_assets::Module::<T>::pcx_issue(claimer, dividend);
146+
let to_referral_or_treasury = dividend / 10.saturated_into();
147+
let reward_splitter = T::GatewayInterface::referral_of(claimer)
148+
.unwrap_or_else(|| T::TreasuryAccount::treasury_account());
149+
Self::transfer(
150+
claimee_reward_pot,
151+
&reward_splitter,
152+
to_referral_or_treasury,
153+
)?;
154+
155+
let to_claimer = dividend - to_referral_or_treasury;
156+
Self::transfer(claimee_reward_pot, claimer, to_claimer)?;
157+
135158
Ok(())
136159
}
137160
}
@@ -151,8 +174,7 @@ impl<T: Trait> Claim<T::AccountId> for Module<T> {
151174
Self::passed_enough_interval(claimer, claimee, frequency_limit, current_block)?;
152175

153176
let claimee_reward_pot = T::DetermineRewardPotAccount::reward_pot_account_for(claimee);
154-
let reward_pot_balance =
155-
<T as xpallet_assets::Trait>::Currency::free_balance(&claimee_reward_pot);
177+
let reward_pot_balance = Self::free_balance(&claimee_reward_pot);
156178

157179
let (dividend, source_weight, target_weight) =
158180
<Self as ComputeMiningWeight<T::AccountId, _>>::compute_dividend(
@@ -164,7 +186,7 @@ impl<T: Trait> Claim<T::AccountId> for Module<T> {
164186

165187
Self::has_enough_staking(claimer, dividend, staking_requirement)?;
166188

167-
Self::allocate_dividend(claimer, claimee, &claimee_reward_pot, dividend)?;
189+
Self::allocate_dividend(&claimee_reward_pot, claimer, dividend)?;
168190

169191
Self::apply_update_miner_mining_weight(claimer, claimee, 0, current_block);
170192
Self::apply_update_asset_mining_weight(
@@ -177,6 +199,8 @@ impl<T: Trait> Claim<T::AccountId> for Module<T> {
177199
miner_ledger.last_claim = Some(current_block);
178200
});
179201

202+
Self::deposit_event(RawEvent::Claim(claimer.clone(), claimee.clone(), dividend));
203+
180204
Ok(())
181205
}
182206
}

xpallets/mining/asset/src/lib.rs

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod tests;
1212

1313
use frame_support::{
1414
decl_error, decl_event, decl_module, decl_storage,
15-
dispatch::DispatchResult,
15+
dispatch::{DispatchError, DispatchResult},
1616
ensure,
1717
storage::IterableStorageMap,
1818
traits::{Currency, ExistenceRequirement},
@@ -42,20 +42,29 @@ pub trait Trait: xpallet_assets::Trait {
4242
/// The overarching event type.
4343
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
4444

45-
///
45+
/// Get the staked balances of asset miner.
4646
type StakingInterface: StakingInterface<Self::AccountId, u128>;
4747

48-
///
48+
/// Get the possible referral of asset miner.
49+
type GatewayInterface: GatewayInterface<Self::AccountId>;
50+
51+
/// Get the treasury account.
4952
type TreasuryAccount: TreasuryAccount<Self::AccountId>;
5053

51-
///
54+
/// Generate the reward pot account for mining asset.
5255
type DetermineRewardPotAccount: RewardPotAccountFor<Self::AccountId, AssetId>;
5356
}
5457

5558
pub trait StakingInterface<AccountId, Balance> {
5659
fn staked_of(who: &AccountId) -> Balance;
5760
}
5861

62+
impl<AccountId, Balance: Default> StakingInterface<AccountId, Balance> for () {
63+
fn staked_of(_: &AccountId) -> Balance {
64+
Default::default()
65+
}
66+
}
67+
5968
impl<T: Trait> StakingInterface<<T as frame_system::Trait>::AccountId, u128> for T
6069
where
6170
T: xpallet_mining_staking::Trait,
@@ -65,23 +74,33 @@ where
6574
}
6675
}
6776

77+
pub trait GatewayInterface<AccountId> {
78+
fn referral_of(who: &AccountId) -> Option<AccountId>;
79+
}
80+
81+
impl<AccountId> GatewayInterface<AccountId> for () {
82+
fn referral_of(_: &AccountId) -> Option<AccountId> {
83+
None
84+
}
85+
}
86+
6887
decl_storage! {
6988
trait Store for Module<T: Trait> as XMiningAsset {
70-
///
89+
/// Possible reward for the new asset owners that does not have native coins yet.
7190
pub DepositReward get(fn deposit_reward): BalanceOf<T> = 100_000.into();
7291

73-
///
92+
/// Can not claim if the claimer violates the restriction.
7493
pub ClaimRestrictionOf get(fn claim_restriction_of):
7594
map hasher(twox_64_concat) AssetId => ClaimRestriction<T::BlockNumber>;
7695

7796
/// External Assets that have the mining rights.
7897
pub MiningPrevilegedAssets get(fn mining_previleged_assets): Vec<AssetId>;
7998

80-
/// Mining weight information of the asset.
99+
/// Mining weight information of the mining assets.
81100
pub AssetLedgers get(fn asset_ledgers):
82101
map hasher(twox_64_concat) AssetId => AssetLedger<T::BlockNumber>;
83102

84-
/// The map from nominator to the vote weight ledger of all nominees.
103+
/// The map from nominator to the vote weight ledger of all mining assets.
85104
pub MinerLedgers get(fn miner_ledgers):
86105
double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) AssetId
87106
=> MinerLedger<T::BlockNumber>;
@@ -113,24 +132,24 @@ decl_event!(
113132
Balance = BalanceOf<T>,
114133
<T as frame_system::Trait>::AccountId,
115134
{
116-
///
117-
Claim(AccountId, AccountId, Balance),
135+
/// Claimed the asset mining rewards. [claimer, asset_id, amount]
136+
Claim(AccountId, AssetId, Balance),
118137
}
119138
);
120139

121140
decl_error! {
122141
/// Error for the staking module.
123142
pub enum Error for Module<T: Trait> {
124143
/// The asset does not have the mining rights.
125-
UnprevilegedAsset,
144+
NotPrevilegedAsset,
126145
/// Claimer does not have enough Staking locked balance.
127146
InsufficientStaking,
128147
/// Claimer just did a claim recently, the next frequency limit is not expired.
129148
UnexpiredFrequencyLimit,
130-
/// Asset error.
131-
AssetError,
132149
/// Zero mining weight.
133-
ZeroMiningWeight
150+
ZeroMiningWeight,
151+
/// Balances error.
152+
DispatchError
134153
}
135154
}
136155

@@ -140,6 +159,12 @@ impl<T: Trait> From<ZeroMiningWeightError> for Error<T> {
140159
}
141160
}
142161

162+
impl<T: Trait> From<DispatchError> for Error<T> {
163+
fn from(_: DispatchError) -> Self {
164+
Self::DispatchError
165+
}
166+
}
167+
143168
decl_module! {
144169
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
145170
type Error = Error<T>;
@@ -153,7 +178,7 @@ decl_module! {
153178

154179
ensure!(
155180
Self::mining_previleged_assets().contains(&target),
156-
Error::<T>::UnprevilegedAsset
181+
Error::<T>::NotPrevilegedAsset
157182
);
158183

159184
<Self as Claim<T::AccountId>>::claim(&sender, &target)?;
@@ -174,6 +199,12 @@ decl_module! {
174199
restriction.frequency_limit = new;
175200
});
176201
}
202+
203+
#[weight = 10]
204+
fn set_x_asset_power(origin, asset_id: AssetId, new: FixedAssetPower) {
205+
ensure_root(origin)?;
206+
XTypeAssetPowerMap::insert(asset_id, new);
207+
}
177208
}
178209
}
179210

@@ -183,6 +214,21 @@ impl<T: Trait> Module<T> {
183214
MinerLedgers::<T>::get(who, asset_id).last_claim
184215
}
185216

217+
#[inline]
218+
fn free_balance(who: &T::AccountId) -> BalanceOf<T> {
219+
<T as xpallet_assets::Trait>::Currency::free_balance(who)
220+
}
221+
222+
#[inline]
223+
fn transfer(from: &T::AccountId, to: &T::AccountId, value: BalanceOf<T>) -> DispatchResult {
224+
<T as xpallet_assets::Trait>::Currency::transfer(
225+
from,
226+
to,
227+
value,
228+
ExistenceRequirement::KeepAlive,
229+
)
230+
}
231+
186232
/// This rule doesn't take effect if the interval is zero.
187233
fn passed_enough_interval(
188234
who: &T::AccountId,
@@ -302,17 +348,14 @@ impl<T: Trait> Module<T> {
302348
Self::update_asset_mining_weight(target, current_block);
303349
}
304350

351+
/// Gives a tiny reward to the depositor in case of it
352+
/// does not have enough balances to claim the mining reward.
305353
fn issue_deposit_reward(depositor: &T::AccountId, target: &AssetId) -> DispatchResult {
306354
let deposit_reward = Self::deposit_reward();
307355
let reward_pot = T::DetermineRewardPotAccount::reward_pot_account_for(target);
308-
let reward_pot_balance = <T as xpallet_assets::Trait>::Currency::free_balance(&reward_pot);
309-
if reward_pot_balance >= deposit_reward {
310-
<T as xpallet_assets::Trait>::Currency::transfer(
311-
&reward_pot,
312-
depositor,
313-
deposit_reward,
314-
ExistenceRequirement::KeepAlive,
315-
)?;
356+
let reward_pot_balance = Self::free_balance(&reward_pot);
357+
if reward_pot_balance >= deposit_reward && Self::free_balance(depositor) <= deposit_reward {
358+
Self::transfer(&reward_pot, depositor, deposit_reward)?;
316359
} else {
317360
warn!("asset {}'s reward pot has only {:?}, skipped issuing deposit reward for depositor {:?}", target, reward_pot_balance, depositor);
318361
}

0 commit comments

Comments
 (0)