Skip to content

Commit

Permalink
Crowdload burn remaining funds (#3707)
Browse files Browse the repository at this point in the history
Crowdloan account should burn all funds after a crowd loan got dissolved
to ensure that the account is reaped correctly.

---------

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
  • Loading branch information
ggwpez and franciscoaguirre authored Mar 17, 2024
1 parent 02e1a7f commit d2a7100
Showing 1 changed file with 45 additions and 4 deletions.
49 changes: 45 additions & 4 deletions polkadot/runtime/common/src/crowdloan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use frame_support::{
pallet_prelude::{DispatchResult, Weight},
storage::{child, ChildTriePrefixIterator},
traits::{
Currency,
Currency, Defensive,
ExistenceRequirement::{self, AllowDeath, KeepAlive},
Get, ReservableCurrency,
},
Expand Down Expand Up @@ -563,6 +563,7 @@ pub mod pallet {
let who = ensure_signed(origin)?;

let fund = Self::funds(index).ok_or(Error::<T>::InvalidParaId)?;
let pot = Self::fund_account_id(fund.fund_index);
let now = frame_system::Pallet::<T>::block_number();

// Only allow dissolution when the raised funds goes to zero,
Expand All @@ -576,7 +577,10 @@ pub mod pallet {
// can take care of that.
debug_assert!(Self::contribution_iterator(fund.fund_index).count().is_zero());

frame_system::Pallet::<T>::dec_providers(&Self::fund_account_id(fund.fund_index))?;
// Crowdloan over, burn all funds.
let _imba = CurrencyOf::<T>::make_free_balance_be(&pot, Zero::zero());
let _ = frame_system::Pallet::<T>::dec_providers(&pot).defensive();

CurrencyOf::<T>::unreserve(&fund.depositor, fund.deposit);
Funds::<T>::remove(index);
Self::deposit_event(Event::<T>::Dissolved { para_id: index });
Expand Down Expand Up @@ -1609,6 +1613,7 @@ mod tests {
new_test_ext().execute_with(|| {
let para = new_para();
let index = NextFundIndex::<Test>::get();
let issuance = Balances::total_issuance();

// Set up a crowdloan
assert_ok!(Crowdloan::create(RuntimeOrigin::signed(1), para, 1000, 1, 1, 9, None));
Expand All @@ -1629,9 +1634,10 @@ mod tests {

// Some funds are left over
assert_eq!(Balances::free_balance(&account_id), 10);
// They wil be left in the account at the end
// Remaining funds will be burned
assert_ok!(Crowdloan::dissolve(RuntimeOrigin::signed(1), para));
assert_eq!(Balances::free_balance(&account_id), 10);
assert_eq!(Balances::free_balance(&account_id), 0);
assert_eq!(Balances::total_issuance(), issuance - 10);
});
}

Expand Down Expand Up @@ -1740,6 +1746,41 @@ mod tests {
});
}

// Regression test to check that a pot account with just one provider can be dissolved.
#[test]
fn dissolve_provider_refs_total_issuance_works() {
new_test_ext().execute_with(|| {
let para = new_para();
let issuance = Balances::total_issuance();

// Set up a crowdloan
assert_ok!(Crowdloan::create(RuntimeOrigin::signed(1), para, 1000, 1, 1, 9, None));
assert_ok!(Crowdloan::contribute(RuntimeOrigin::signed(2), para, 100, None));
assert_ok!(Crowdloan::contribute(RuntimeOrigin::signed(3), para, 50, None));

run_to_block(10);

// We test the historic case where crowdloan accounts only have one provider:
{
let fund = Crowdloan::funds(para).unwrap();
let pot = Crowdloan::fund_account_id(fund.fund_index);
System::dec_providers(&pot).unwrap();
assert_eq!(System::providers(&pot), 1);
}

// All funds are refunded
assert_ok!(Crowdloan::refund(RuntimeOrigin::signed(2), para));

// Now that `fund.raised` is zero, it can be dissolved.
assert_ok!(Crowdloan::dissolve(RuntimeOrigin::signed(1), para));

assert_eq!(Balances::free_balance(1), 1000);
assert_eq!(Balances::free_balance(2), 2000);
assert_eq!(Balances::free_balance(3), 3000);
assert_eq!(Balances::total_issuance(), issuance);
});
}

#[test]
fn dissolve_works() {
new_test_ext().execute_with(|| {
Expand Down

0 comments on commit d2a7100

Please sign in to comment.