Skip to content

Commit 2b4ca41

Browse files
committed
Init commit
1 parent 4727b60 commit 2b4ca41

File tree

16 files changed

+583
-365
lines changed

16 files changed

+583
-365
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/collator-selection/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,11 @@ pub mod pallet {
502502
})
503503
.collect::<Vec<_>>()
504504
}
505+
506+
/// Check whether an account is a candidate.
507+
pub fn is_account_candidate(account: &T::AccountId) -> bool {
508+
Self::candidates().iter().any(|c| &c.who == account)
509+
}
505510
}
506511

507512
/// Keep track of number of authored blocks per authority, uncles are counted as well since

pallets/dapp-staking-migration/src/lib.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ pub mod pallet {
168168
impl<T: Config> Pallet<T> {
169169
/// Execute migrations steps until the specified weight limit has been consumed.
170170
///
171-
/// Depending on the number of entries migrated and/or deleted, appropriate events are emited.
171+
/// Depending on the number of entries migrated and/or deleted, appropriate events are emitted.
172172
///
173173
/// In case at least some progress is made, `Ok(_)` is returned.
174174
/// If no progress is made, `Err(_)` is returned.
@@ -295,7 +295,7 @@ pub mod pallet {
295295
/// Steps:
296296
/// 1. Attempt to `drain` a single DB entry from the old storage. If it's unregistered, move on.
297297
/// 2. Unreserve the old `RegisterDeposit` amount from the developer account.
298-
/// 2. Re-decode old smart contract type into new one. Operation should be infalible in practice since the same underlying type is used.
298+
/// 2. Re-decode old smart contract type into new one. Operation should be infallible in practice since the same underlying type is used.
299299
/// 3. `register` the old-new smart contract into dApp staking v3 pallet.
300300
///
301301
/// Returns `Ok(_)` if an entry was migrated, `Err(_)` if there are no more entries to migrate.
@@ -348,13 +348,6 @@ pub mod pallet {
348348
smart_contract,
349349
error,
350350
);
351-
352-
// This should never happen, but if it does, we want to know about it.
353-
#[cfg(feature = "try-runtime")]
354-
panic!(
355-
"Failed to register smart contract: {:?} with error: {:?}.",
356-
smart_contract, error
357-
);
358351
}
359352
}
360353

@@ -383,7 +376,7 @@ pub mod pallet {
383376
let locked = old_account_ledger.locked;
384377

385378
// Old unbonding amount can just be released, to keep things simple.
386-
// Alternative is to re-calculat this into unlocking chunks.
379+
// Alternative is to re-calculate this into unlocking chunks.
387380
let _total_unbonding = old_account_ledger.unbonding_info.sum();
388381

389382
<T as pallet_dapps_staking::Config>::Currency::remove_lock(
@@ -430,7 +423,7 @@ pub mod pallet {
430423
/// Used to remove one entry from the old _dapps_staking_v2_ storage.
431424
///
432425
/// If there are no more entries to remove, returns `Err(_)` with consumed weight and number of deleted entries.
433-
/// Otherwise returns `Ok(_)` with consumed weight and number of consumed enries.
426+
/// Otherwise returns `Ok(_)` with consumed weight and number of consumed entries.
434427
pub(crate) fn cleanup_old_storage(limit: u32) -> Result<(Weight, u32), (Weight, u32)> {
435428
let hashed_prefix = twox_128(pallet_dapps_staking::Pallet::<T>::name().as_bytes());
436429

@@ -474,8 +467,8 @@ pub mod pallet {
474467

475468
/// Min allowed weight that migration should be allowed to consume.
476469
///
477-
/// This serves as a safety marging, to prevent accidental overspending, due to
478-
/// inprecision in implementation or benchmarks, when small weight limit is specified.
470+
/// This serves as a safety margin, to prevent accidental overspending, due to
471+
/// imprecision in implementation or benchmarks, when small weight limit is specified.
479472
pub(crate) fn min_call_weight() -> Weight {
480473
// 5% of block should be fine
481474
T::BlockWeights::get().max_block / 10

pallets/dapp-staking-v3/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-dapp-staking-v3"
3-
version = "0.0.1-alpha"
3+
version = "0.1.0"
44
description = "Pallet for dApp staking v3 protocol"
55
authors.workspace = true
66
edition.workspace = true

pallets/dapp-staking-v3/src/benchmarking/mod.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ mod benchmarks {
151151
}
152152

153153
#[benchmark]
154-
fn lock() {
154+
fn lock_new_account() {
155155
initial_config::<T>();
156156

157157
let staker: T::AccountId = whitelisted_caller();
@@ -167,7 +167,7 @@ mod benchmarks {
167167
T::BenchmarkHelper::set_balance(&staker, amount);
168168

169169
#[extrinsic_call]
170-
_(RawOrigin::Signed(staker.clone()), amount);
170+
lock(RawOrigin::Signed(staker.clone()), amount);
171171

172172
assert_last_event::<T>(
173173
Event::<T>::Locked {
@@ -178,6 +178,39 @@ mod benchmarks {
178178
);
179179
}
180180

181+
#[benchmark]
182+
fn lock_existing_account() {
183+
initial_config::<T>();
184+
185+
let staker: T::AccountId = whitelisted_caller();
186+
let owner: T::AccountId = account("dapp_owner", 0, SEED);
187+
let smart_contract = T::BenchmarkHelper::get_smart_contract(1);
188+
assert_ok!(DappStaking::<T>::register(
189+
RawOrigin::Root.into(),
190+
owner.clone().into(),
191+
smart_contract.clone(),
192+
));
193+
194+
let amount_1 = T::MinimumLockedAmount::get();
195+
let amount_2 = 19;
196+
T::BenchmarkHelper::set_balance(&staker, amount_1 + amount_2);
197+
assert_ok!(DappStaking::<T>::lock(
198+
RawOrigin::Signed(staker.clone()).into(),
199+
amount_1,
200+
));
201+
202+
#[extrinsic_call]
203+
lock(RawOrigin::Signed(staker.clone()), amount_2);
204+
205+
assert_last_event::<T>(
206+
Event::<T>::Locked {
207+
account: staker,
208+
amount: amount_2,
209+
}
210+
.into(),
211+
);
212+
}
213+
181214
#[benchmark]
182215
fn unlock() {
183216
initial_config::<T>();

pallets/dapp-staking-v3/src/lib.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ pub use sp_std::vec::Vec;
5252

5353
use astar_primitives::{
5454
dapp_staking::{
55-
CycleConfiguration, DAppId, EraNumber, Observer as DAppStakingObserver, PeriodNumber,
56-
SmartContractHandle, StakingRewardHandler, TierId,
55+
AccountCheck, CycleConfiguration, DAppId, EraNumber, Observer as DAppStakingObserver,
56+
PeriodNumber, SmartContractHandle, StakingRewardHandler, TierId,
5757
},
5858
oracle::PriceProvider,
5959
Balance, BlockNumber,
@@ -144,6 +144,9 @@ pub mod pallet {
144144
/// dApp staking event observers, notified when certain events occur.
145145
type Observers: DAppStakingObserver;
146146

147+
/// Used to check whether an account is allowed to participate in dApp staking.
148+
type AccountCheck: AccountCheck<Self::AccountId>;
149+
147150
/// Maximum length of a single era reward span length entry.
148151
#[pallet::constant]
149152
type EraRewardSpanLength: Get<u32>;
@@ -307,6 +310,8 @@ pub mod pallet {
307310
ZeroAmount,
308311
/// Total locked amount for staker is below minimum threshold.
309312
LockedAmountBelowThreshold,
313+
/// Account is not allowed to participate in dApp staking due to some external reason (e.g. account is already a collator).
314+
AccountNotAvailableForDappStaking,
310315
/// Cannot add additional unlocking chunks due to capacity limit.
311316
TooManyUnlockingChunks,
312317
/// Remaining stake prevents entire balance of starting the unlocking process.
@@ -765,16 +770,30 @@ pub mod pallet {
765770
///
766771
/// Locked amount can immediately be used for staking.
767772
#[pallet::call_index(7)]
768-
#[pallet::weight(T::WeightInfo::lock())]
769-
pub fn lock(origin: OriginFor<T>, #[pallet::compact] amount: Balance) -> DispatchResult {
773+
#[pallet::weight(T::WeightInfo::lock_new_account().max(T::WeightInfo::lock_existing_account()))]
774+
pub fn lock(
775+
origin: OriginFor<T>,
776+
#[pallet::compact] amount: Balance,
777+
) -> DispatchResultWithPostInfo {
770778
Self::ensure_pallet_enabled()?;
771779
let account = ensure_signed(origin)?;
772780

773781
let mut ledger = Ledger::<T>::get(&account);
774782

783+
// Only do the check for new accounts.
784+
// External logic should ensure that accounts which are already participating in dApp staking aren't
785+
// allowed to participate elsewhere where they shouldn't.
786+
let is_new_account = ledger.is_empty();
787+
if is_new_account {
788+
ensure!(
789+
T::AccountCheck::allowed_to_stake(&account),
790+
Error::<T>::AccountNotAvailableForDappStaking
791+
);
792+
}
793+
775794
// Calculate & check amount available for locking
776795
let available_balance =
777-
T::Currency::balance(&account).saturating_sub(ledger.active_locked_amount());
796+
T::Currency::total_balance(&account).saturating_sub(ledger.active_locked_amount());
778797
let amount_to_lock = available_balance.min(amount);
779798
ensure!(!amount_to_lock.is_zero(), Error::<T>::ZeroAmount);
780799

@@ -795,7 +814,12 @@ pub mod pallet {
795814
amount: amount_to_lock,
796815
});
797816

798-
Ok(())
817+
Ok(Some(if is_new_account {
818+
T::WeightInfo::lock_new_account()
819+
} else {
820+
T::WeightInfo::lock_existing_account()
821+
})
822+
.into())
799823
}
800824

801825
/// Attempts to start the unlocking process for the specified amount.

pallets/dapp-staking-v3/src/test/mock.rs

+9
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,14 @@ impl DappStakingObserver for DummyDappStakingObserver {
193193
}
194194
}
195195

196+
pub(crate) const BLACKLISTED_ACCOUNT: AccountId = 789456123;
197+
pub struct DummyAccountCheck;
198+
impl AccountCheck<AccountId> for DummyAccountCheck {
199+
fn allowed_to_stake(account: &AccountId) -> bool {
200+
*account != BLACKLISTED_ACCOUNT
201+
}
202+
}
203+
196204
impl pallet_dapp_staking::Config for Test {
197205
type RuntimeEvent = RuntimeEvent;
198206
type RuntimeFreezeReason = RuntimeFreezeReason;
@@ -203,6 +211,7 @@ impl pallet_dapp_staking::Config for Test {
203211
type StakingRewardHandler = DummyStakingRewardHandler;
204212
type CycleConfiguration = DummyCycleConfiguration;
205213
type Observers = DummyDappStakingObserver;
214+
type AccountCheck = DummyAccountCheck;
206215
type EraRewardSpanLength = ConstU32<8>;
207216
type RewardRetentionInPeriods = ConstU32<2>;
208217
type MaxNumberOfContracts = ConstU32<10>;

pallets/dapp-staking-v3/src/test/testing_utils.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626

2727
use frame_support::{
2828
assert_ok,
29-
traits::{fungible::InspectFreeze, Get, OnIdle},
29+
traits::{fungible::InspectFreeze, Currency, Get, OnIdle},
3030
weights::Weight,
3131
};
3232
use sp_runtime::{traits::Zero, Perbill};
@@ -208,11 +208,11 @@ pub(crate) fn assert_unregister(smart_contract: &MockSmartContract) {
208208
pub(crate) fn assert_lock(account: AccountId, amount: Balance) {
209209
let pre_snapshot = MemorySnapshot::new();
210210

211-
let free_balance = Balances::free_balance(&account);
211+
let total_balance = Balances::total_balance(&account);
212212
let locked_balance = pre_snapshot.locked_balance(&account);
213213
let init_frozen_balance = Balances::balance_frozen(&FreezeReason::DAppStaking.into(), &account);
214214

215-
let available_balance = free_balance
215+
let available_balance = total_balance
216216
.checked_sub(locked_balance)
217217
.expect("Locked amount cannot be greater than available free balance");
218218
let expected_lock_amount = available_balance.min(amount);

pallets/dapp-staking-v3/src/test/tests.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ use crate::{
2525
use frame_support::{
2626
assert_noop, assert_ok, assert_storage_noop,
2727
error::BadOrigin,
28-
traits::{fungible::Unbalanced as FunUnbalanced, Currency, Get, OnFinalize, OnInitialize},
28+
traits::{
29+
fungible::Unbalanced as FunUnbalanced, Currency, Get, OnFinalize, OnInitialize,
30+
ReservableCurrency,
31+
},
2932
};
3033
use sp_runtime::traits::Zero;
3134

@@ -473,7 +476,7 @@ fn lock_is_ok() {
473476
ExtBuilder::build().execute_with(|| {
474477
// Lock some amount
475478
let locker = 2;
476-
let free_balance = Balances::free_balance(&locker);
479+
let free_balance = Balances::total_balance(&locker);
477480
assert!(free_balance > 500, "Sanity check");
478481
assert_lock(locker, 100);
479482
assert_lock(locker, 200);
@@ -487,6 +490,25 @@ fn lock_is_ok() {
487490
})
488491
}
489492

493+
#[test]
494+
fn lock_with_reserve_is_ok() {
495+
ExtBuilder::build().execute_with(|| {
496+
// Prepare locker account
497+
let locker = 30;
498+
let minimum_locked_amount: Balance = <Test as Config>::MinimumLockedAmount::get();
499+
Balances::make_free_balance_be(&locker, minimum_locked_amount);
500+
assert_ok!(Balances::reserve(&locker, 1));
501+
assert_eq!(
502+
Balances::free_balance(&locker),
503+
minimum_locked_amount - 1,
504+
"Sanity check post-reserve."
505+
);
506+
507+
// Lock must still work since account is not blacklisted and has enough total balance to cover the lock requirement
508+
assert_lock(locker, minimum_locked_amount);
509+
})
510+
}
511+
490512
#[test]
491513
fn lock_with_incorrect_amount_fails() {
492514
ExtBuilder::build().execute_with(|| {
@@ -499,7 +521,7 @@ fn lock_with_incorrect_amount_fails() {
499521
// Attempting to lock something after everything has been locked is same
500522
// as attempting to lock with "nothing"
501523
let locker = 1;
502-
assert_lock(locker, Balances::free_balance(&locker));
524+
assert_lock(locker, Balances::total_balance(&locker));
503525
assert_noop!(
504526
DappStaking::lock(RuntimeOrigin::signed(locker), 1),
505527
Error::<Test>::ZeroAmount,
@@ -515,6 +537,18 @@ fn lock_with_incorrect_amount_fails() {
515537
})
516538
}
517539

540+
#[test]
541+
fn lock_with_blacklisted_account_fails() {
542+
ExtBuilder::build().execute_with(|| {
543+
Balances::make_free_balance_be(&BLACKLISTED_ACCOUNT, 100000);
544+
545+
assert_noop!(
546+
DappStaking::lock(RuntimeOrigin::signed(BLACKLISTED_ACCOUNT), 1000),
547+
Error::<Test>::AccountNotAvailableForDappStaking,
548+
);
549+
})
550+
}
551+
518552
#[test]
519553
fn unbond_and_unstake_is_ok() {
520554
ExtBuilder::build().execute_with(|| {

0 commit comments

Comments
 (0)