Skip to content

Commit ab724df

Browse files
refac(torus0): stake in reserved balance (#116)
This change prevents errors that might happen when we wrongly track stake changes. By moving to reserved balances, we avoid minting tokens when unstaking from accounts. Closes CHAIN-104.
1 parent c8947d6 commit ab724df

File tree

13 files changed

+281
-126
lines changed

13 files changed

+281
-126
lines changed

pallets/emission0/src/distribute.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,11 @@ fn linear_rewards<T: Config>(mut emission: NegativeImbalanceOf<T>) -> NegativeIm
375375
);
376376

377377
let raw_amount = amount.peek();
378+
378379
T::Currency::resolve_creating(&staker, amount);
379-
let _ = <T::Torus>::stake_to(&staker, &input.agent_id, raw_amount);
380+
if let Err(err) = <T::Torus>::stake_to(&staker, &input.agent_id, raw_amount) {
381+
error!("failed to stake {raw_amount} tokens to {staker:?}: {err:?}");
382+
}
380383
};
381384

382385
if dividend.peek() != 0 {

pallets/emission0/src/migrations.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use polkadot_sdk::frame_support::{
55
use crate::{Config, Pallet};
66

77
pub mod v2 {
8-
use polkadot_sdk::sp_std::collections::btree_set::BTreeSet;
8+
use polkadot_sdk::{sp_std::collections::btree_set::BTreeSet, sp_tracing::error};
99

1010
use pallet_emission0_api::Emission0Api;
1111
use pallet_governance_api::GovernanceApi;
@@ -30,13 +30,13 @@ pub mod v2 {
3030
&agent, allocator,
3131
)
3232
{
33-
polkadot_sdk::sp_tracing::error!(
33+
error!(
3434
"failed to delegate weight control from {agent:?} to {allocator:?}: {err:?}"
3535
);
3636
}
3737
}
3838
} else {
39-
polkadot_sdk::sp_tracing::error!("no allocators available");
39+
error!("no allocators available");
4040
}
4141

4242
Weight::zero()

pallets/emission0/tests/distribution.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use pallet_emission0::{
88
PendingEmission, WeightControlDelegation,
99
};
1010
use polkadot_sdk::{
11+
frame_support::traits::Currency,
1112
pallet_balances,
1213
sp_core::Get,
1314
sp_runtime::{BoundedVec, FixedU128, Perbill, Percent},
@@ -19,7 +20,7 @@ use test_utils::{
1920
stake::sum_staked_by, Agents, FeeConstraints, MaxAllowedValidators, MinAllowedStake,
2021
MinValidatorStake, StakedBy,
2122
},
22-
register_empty_agent, step_block, Test,
23+
register_empty_agent, step_block, AccountId, Balances, ExistentialDeposit, Test,
2324
};
2425

2526
#[test]
@@ -396,6 +397,9 @@ fn pays_dividends_to_stakers() {
396397
ConsensusMembers::<Test>::set(miner, Some(Default::default()));
397398

398399
for id in [validator, miner] {
400+
let _ =
401+
<Balances as Currency<AccountId>>::deposit_creating(&id, ExistentialDeposit::get());
402+
399403
register_empty_agent(id);
400404
}
401405

@@ -594,6 +598,9 @@ fn pays_weight_delegation_fee_to_validators_without_permits() {
594598
ConsensusMembers::<Test>::set(miner, Some(Default::default()));
595599

596600
for id in [val_1, val_2, miner] {
601+
let _ =
602+
<Balances as Currency<AccountId>>::deposit_creating(&id, ExistentialDeposit::get());
603+
597604
register_empty_agent(id);
598605
}
599606

pallets/faucet/tests/faucet.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ impl pallet_torus0::Config for Test {
148148
type RuntimeEvent = RuntimeEvent;
149149

150150
type Currency = Balances;
151+
type ExistentialDeposit = ExistentialDeposit;
151152

152153
type Governance = Governance;
153154

@@ -273,7 +274,7 @@ impl pallet_balances::Config for Test {
273274
type MaxLocks = MaxLocks;
274275
type WeightInfo = ();
275276
type MaxReserves = MaxReserves;
276-
type ReserveIdentifier = ();
277+
type ReserveIdentifier = [u8; 8];
277278
type RuntimeHoldReason = ();
278279
type FreezeIdentifier = ();
279280
type MaxFreezes = polkadot_sdk::frame_support::traits::ConstU32<16>;

pallets/governance/tests/voting.rs

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ use polkadot_sdk::{frame_support::assert_ok, sp_runtime::Percent};
1111
use polkadot_sdk::{frame_support::traits::Get, sp_runtime::BoundedVec};
1212
use test_utils::{
1313
add_balance, as_tors, get_balance, get_origin, new_test_ext, step_block, zero_min_burn,
14-
AccountId, Governance, Test,
14+
AccountId, ExistentialDeposit, Governance, Test,
1515
};
1616

17-
fn register(account: AccountId, _unused: u16, module: AccountId, stake: u128) {
18-
if get_balance(account) < stake {
19-
add_balance(account, stake);
17+
fn register(account: AccountId, module: AccountId, stake: u128) {
18+
let ed = ExistentialDeposit::get();
19+
let cost = {
20+
let config = pallet_governance::GlobalGovernanceConfig::<Test>::get();
21+
config.proposal_cost.max(config.agent_application_cost)
22+
};
23+
if get_balance(account) < stake + ed + cost {
24+
add_balance(account, stake + ed + cost);
2025
}
2126

2227
let _ = pallet_governance::whitelist::add_to_whitelist::<Test>(module);
@@ -28,17 +33,9 @@ fn register(account: AccountId, _unused: u16, module: AccountId, stake: u128) {
2833
b"metadata".to_vec(),
2934
));
3035

31-
assert!(get_balance(account) >= stake);
32-
33-
let min_stake: u128 = pallet_torus0::MinAllowedStake::<Test>::get();
34-
if stake >= min_stake {
35-
if get_balance(account) - stake < 1 {
36-
add_balance(account, 1);
37-
}
38-
assert_ok!(pallet_torus0::stake::add_stake::<Test>(
39-
account, module, stake
40-
));
41-
}
36+
assert_ok!(pallet_torus0::stake::add_stake::<Test>(
37+
account, module, stake
38+
));
4239
}
4340

4441
fn config(proposal_cost: u128, proposal_expiration: u64) {
@@ -76,16 +73,15 @@ pub fn stake(account: u32, module: u32, stake: u128) {
7673
fn removes_vote_correctly() {
7774
new_test_ext().execute_with(|| {
7875
zero_min_burn();
76+
config(1, 100);
7977

8078
const FOR: u32 = 0;
8179
const AGAINST: u32 = 1;
8280

8381
let key = 0;
8482

85-
register(FOR, 0, 0, as_tors(10));
86-
register(AGAINST, 0, 1, as_tors(5));
87-
88-
config(1, 100);
83+
register(FOR, 0, as_tors(10));
84+
register(AGAINST, 1, as_tors(5));
8985

9086
add_balance(key, 1);
9187
assert_ok!(
@@ -114,18 +110,18 @@ fn removes_vote_correctly() {
114110
#[test]
115111
fn global_proposal_is_refused_correctly() {
116112
new_test_ext().execute_with(|| {
113+
zero_min_burn();
114+
config(1, 100);
115+
117116
PendingEmission::<Test>::set(0);
118117
TreasuryEmissionFee::<Test>::set(Percent::zero());
119118
let balance = get_balance(DaoTreasuryAddress::<Test>::get());
120119

121-
zero_min_burn();
122120
const FOR: u32 = 0;
123121
const AGAINST: u32 = 1;
124122

125-
register(FOR, 0, 0, as_tors(5));
126-
register(AGAINST, 0, 1, as_tors(10));
127-
128-
config(1, 100);
123+
register(FOR, 0, as_tors(5));
124+
register(AGAINST, 1, as_tors(10));
129125

130126
assert_ok!(
131127
pallet_governance::Pallet::<Test>::add_global_custom_proposal(
@@ -163,14 +159,13 @@ fn global_proposal_is_refused_correctly() {
163159
fn adds_vote_correctly() {
164160
new_test_ext().execute_with(|| {
165161
zero_min_burn();
162+
config(1, 100);
166163

167164
const FOR: u32 = 0;
168165
const AGAINST: u32 = 1;
169166

170-
register(FOR, 0, 0, as_tors(10));
171-
register(AGAINST, 0, 1, as_tors(10));
172-
173-
config(1, 100);
167+
register(FOR, 0, as_tors(10));
168+
register(AGAINST, 1, as_tors(10));
174169

175170
assert_ok!(
176171
pallet_governance::Pallet::<Test>::add_global_custom_proposal(
@@ -200,6 +195,7 @@ fn adds_vote_correctly() {
200195
fn ensures_proposal_exists() {
201196
new_test_ext().execute_with(|| {
202197
zero_min_burn();
198+
config(1, 100);
203199

204200
const MODULE: u32 = 0;
205201
PendingEmission::<Test>::set(0);
@@ -210,11 +206,9 @@ fn ensures_proposal_exists() {
210206
let default_proposal_expiration: u64 =
211207
<Test as pallet_governance::Config>::DefaultProposalExpiration::get();
212208

213-
config(1, 100);
214-
215209
let origin = get_origin(0);
216210
add_balance(0, as_tors(2));
217-
register(0, 0, 0, as_tors(1) - min_stake);
211+
register(0, 0, as_tors(1) - min_stake);
218212

219213
if pallet_torus0::stake::sum_staked_by::<Test>(&MODULE) < 1 {
220214
stake(MODULE, MODULE, as_tors(1));
@@ -249,20 +243,19 @@ fn ensures_proposal_exists() {
249243
#[test]
250244
fn creates_emission_proposal_with_invalid_params_and_it_fails() {
251245
new_test_ext().execute_with(|| {
252-
const MODULE: AccountId = 0;
253-
254246
zero_min_burn();
255247

256248
let default_proposal_expiration: u64 =
257249
<Test as pallet_governance::Config>::DefaultProposalExpiration::get();
250+
config(1, default_proposal_expiration);
258251

259-
let min_stake: u128 = <Test as pallet_torus0::Config>::DefaultMinAllowedStake::get();
252+
const MODULE: AccountId = 0;
260253

261-
config(1, default_proposal_expiration);
254+
let min_stake: u128 = <Test as pallet_torus0::Config>::DefaultMinAllowedStake::get();
262255

263256
let origin = get_origin(MODULE);
264257
add_balance(MODULE, as_tors(2));
265-
register(MODULE, 0, MODULE, as_tors(1) - min_stake);
258+
register(MODULE, MODULE, as_tors(1) - min_stake);
266259

267260
assert_err!(
268261
pallet_governance::Pallet::<Test>::vote_proposal(origin.clone(), 0, true),
@@ -285,12 +278,11 @@ fn creates_emission_proposal_with_invalid_params_and_it_fails() {
285278
fn ensures_proposal_is_open() {
286279
new_test_ext().execute_with(|| {
287280
zero_min_burn();
281+
config(1, 100);
288282

289283
const MODULE: u32 = 0;
290284

291-
register(MODULE, 0, 0, as_tors(10));
292-
293-
config(1, 100);
285+
register(MODULE, 0, as_tors(10));
294286

295287
Proposals::<Test>::set(
296288
0,
@@ -327,12 +319,11 @@ fn ensures_proposal_is_open() {
327319
fn ensures_module_hasnt_voted() {
328320
new_test_ext().execute_with(|| {
329321
zero_min_burn();
322+
config(1, 100);
330323

331324
const MODULE: u32 = 0;
332325

333-
register(MODULE, 0, 0, as_tors(10));
334-
335-
config(1, 100);
326+
register(MODULE, 0, as_tors(10));
336327

337328
assert_ok!(
338329
pallet_governance::Pallet::<Test>::add_global_custom_proposal(
@@ -358,12 +349,11 @@ fn ensures_module_hasnt_voted() {
358349
fn ensures_module_has_voted() {
359350
new_test_ext().execute_with(|| {
360351
zero_min_burn();
352+
config(1, 100);
361353

362354
const MODULE: u32 = 0;
363355

364-
register(MODULE, 0, 0, as_tors(10));
365-
366-
config(1, 100);
356+
register(MODULE, 0, as_tors(10));
367357

368358
assert_ok!(
369359
pallet_governance::Pallet::<Test>::add_global_custom_proposal(

pallets/torus0/api/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use core::{
1010

1111
use codec::{Decode, Encode, MaxEncodedLen};
1212
use polkadot_sdk::{
13+
frame_support::dispatch::DispatchResult,
1314
sp_core::ConstU32,
1415
sp_runtime::{BoundedVec, Percent},
1516
sp_std::vec::Vec,
@@ -33,7 +34,7 @@ pub trait Torus0Api<AccountId, Balance> {
3334
fn sum_staking_to(staker: &AccountId) -> Balance;
3435

3536
fn staked_by(staked: &AccountId) -> alloc::vec::Vec<(AccountId, Balance)>;
36-
fn stake_to(staker: &AccountId, staked: &AccountId, amount: Balance) -> Result<(), Balance>;
37+
fn stake_to(staker: &AccountId, staked: &AccountId, amount: Balance) -> DispatchResult;
3738

3839
fn agent_ids() -> impl Iterator<Item = AccountId>;
3940
fn is_agent_registered(agent: &AccountId) -> bool;
@@ -47,7 +48,7 @@ pub trait Torus0Api<AccountId, Balance> {
4748
name: alloc::vec::Vec<u8>,
4849
url: alloc::vec::Vec<u8>,
4950
metadata: alloc::vec::Vec<u8>,
50-
) -> polkadot_sdk::frame_support::dispatch::DispatchResult;
51+
) -> DispatchResult;
5152

5253
#[doc(hidden)]
5354
#[cfg(feature = "runtime-benchmarks")]

pallets/torus0/src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ use crate::{agent::Agent, burn::BurnConfiguration, fee::ValidatorFeeConstraints}
3434

3535
#[frame::pallet]
3636
pub mod pallet {
37-
const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
37+
const STORAGE_VERSION: StorageVersion = StorageVersion::new(6);
3838

3939
use frame::prelude::BlockNumberFor;
4040
use pallet_emission0_api::Emission0Api;
4141
use pallet_governance_api::GovernanceApi;
4242
use pallet_permission0_api::Permission0NamespacesApi;
4343
use pallet_torus0_api::NamespacePathInner;
44-
use polkadot_sdk::frame_support::traits::ReservableCurrency;
44+
use polkadot_sdk::frame_support::traits::{NamedReservableCurrency, ReservableCurrency};
4545
use weights::WeightInfo;
4646

4747
use super::*;
@@ -257,8 +257,10 @@ pub mod pallet {
257257

258258
type Currency: Currency<Self::AccountId, Balance = u128>
259259
+ ReservableCurrency<Self::AccountId>
260+
+ NamedReservableCurrency<Self::AccountId, ReserveIdentifier = [u8; 8]>
260261
+ Send
261262
+ Sync;
263+
type ExistentialDeposit: Get<BalanceOf<Self>>;
262264

263265
type Governance: GovernanceApi<Self::AccountId>;
264266

@@ -577,8 +579,8 @@ impl<T: Config>
577579
staker: &T::AccountId,
578580
staked: &T::AccountId,
579581
amount: <T::Currency as Currency<T::AccountId>>::Balance,
580-
) -> Result<(), <T::Currency as Currency<T::AccountId>>::Balance> {
581-
stake::add_stake::<T>(staker.clone(), staked.clone(), amount).map_err(|_| amount)
582+
) -> DispatchResult {
583+
stake::add_stake::<T>(staker.clone(), staked.clone(), amount)
582584
}
583585

584586
fn agent_ids() -> impl Iterator<Item = T::AccountId> {

0 commit comments

Comments
 (0)