Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions node/primitives/src/salp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub enum ContributionStatus<BalanceOf> {
Refunded,
Unlocked,
Redeemed,
MigratedIdle,
MigrateToIdle,
}

#[derive(Encode, Decode, Clone, PartialEq, Eq, Copy, RuntimeDebug)]
Expand Down Expand Up @@ -64,7 +64,7 @@ where
Self::Refunded => RpcContributionStatus::Refunded,
Self::Unlocked => RpcContributionStatus::Unlocked,
Self::Redeemed => RpcContributionStatus::Redeemed,
Self::MigratedIdle => RpcContributionStatus::MigratedIdle,
Self::MigrateToIdle => RpcContributionStatus::MigratedIdle,
};
rpc_status
}
Expand Down
92 changes: 53 additions & 39 deletions pallets/salp-lite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,17 @@ pub mod pallet {
#[pallet::getter(fn redeem_pool)]
pub(super) type RedeemPool<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;

/// Funds to migrate
#[pallet::storage]
#[pallet::getter(fn to_migrate_funds)]
pub(super) type FundsToMigrate<T: Config> = StorageMap<
_,
Blake2_128Concat,
ParaId,
Option<FundInfo<BalanceOf<T>, LeasePeriod>>,
ValueQuery,
>;

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight((
Expand Down Expand Up @@ -355,8 +366,7 @@ pub mod pallet {
None => fund.status,
Some(status) => status,
};

Funds::<T>::insert(
FundsToMigrate::<T>::insert(
index,
Some(FundInfo {
cap,
Expand All @@ -367,66 +377,70 @@ pub mod pallet {
trie_index: fund.trie_index,
}),
);

Self::deposit_event(Event::<T>::Edited(index));
Ok(())
}

/// Unlock the reserved vsToken/vsBond after fund success
#[pallet::weight((
0,
DispatchClass::Normal,
Pays::No
))]
#[pallet::weight(T::WeightInfo::batch_unlock(T::BatchKeysLimit::get()))]
#[transactional]
pub fn batch_migrate(
origin: OriginFor<T>,
#[pallet::compact] index: ParaId,
first_slot: LeasePeriod,
last_slot: LeasePeriod,
) -> DispatchResult {
T::EnsureConfirmAsMultiSig::ensure_origin(origin)?;

ensure_signed(origin)?;
let fund = Self::funds(index).ok_or(Error::<T>::InvalidParaId)?;
ensure!(
fund.status == FundStatus::Failed || fund.status == FundStatus::RefundWithdrew,
Error::<T>::InvalidFundStatus
);

ensure!(first_slot > fund.first_slot, Error::<T>::MigrateSlotBeforeFirstSlot);
let to_migrate_fund = Self::to_migrate_funds(index).ok_or(Error::<T>::InvalidParaId)?;

let mut migrate_count = 0u32;
let contributions = Self::contribution_iterator(fund.trie_index);
let mut all_migrated = true;

for (who, (contributed, status)) in contributions {
if migrate_count >= T::BatchKeysLimit::get() {
// Not everyone was able to be refunded this time around.
all_migrated = false;
break;
}
if status != ContributionStatus::MigratedIdle {
#[allow(non_snake_case)]
let (_, vsBond) = Self::vsAssets(index, fund.first_slot, fund.last_slot);

let balance = T::MultiCurrency::slash_reserved(vsBond, &who, contributed);
ensure!(balance == Zero::zero(), Error::<T>::NotEnoughReservedAssetsToRefund);

let (_, vs_bond_new) = Self::vsAssets(index, first_slot, last_slot);
T::MultiCurrency::deposit(vs_bond_new, &who, contributed)?;
T::MultiCurrency::reserve(vs_bond_new, &who, contributed)?;

Self::put_contribution(
fund.trie_index,
&who,
contributed,
ContributionStatus::MigratedIdle,
);
migrate_count += 1;
if fund.first_slot != to_migrate_fund.first_slot ||
fund.last_slot != to_migrate_fund.last_slot
{
for (who, (contributed, status)) in contributions {
if migrate_count >= T::BatchKeysLimit::get() {
// Not everyone was able to be refunded this time around.
all_migrated = false;
break;
}
if status != ContributionStatus::MigrateToIdle {
#[allow(non_snake_case)]
let (_, vsBond) = Self::vsAssets(index, fund.first_slot, fund.last_slot);

let balance = T::MultiCurrency::slash_reserved(vsBond, &who, contributed);
ensure!(
balance == Zero::zero(),
Error::<T>::NotEnoughReservedAssetsToRefund
);

let (_, vs_bond_new) = Self::vsAssets(
index,
to_migrate_fund.first_slot,
to_migrate_fund.last_slot,
);
T::MultiCurrency::deposit(vs_bond_new, &who, contributed)?;
T::MultiCurrency::reserve(vs_bond_new, &who, contributed)?;

Self::put_contribution(
fund.trie_index,
&who,
contributed,
ContributionStatus::MigrateToIdle,
);
migrate_count += 1;
}
}
}

if all_migrated {
FundsToMigrate::<T>::remove(index);
Funds::<T>::insert(index, Some(to_migrate_fund));
Self::deposit_event(Event::<T>::AllMigrated(index));
}

Expand Down Expand Up @@ -595,7 +609,7 @@ pub mod pallet {

let (contributed, status) = Self::contribution(fund.trie_index, &who);
ensure!(
status == ContributionStatus::Idle || status == ContributionStatus::MigratedIdle,
status == ContributionStatus::Idle || status == ContributionStatus::MigrateToIdle,
Error::<T>::InvalidContributionStatus
);

Expand Down
48 changes: 16 additions & 32 deletions pallets/salp-lite/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,54 +931,38 @@ fn batch_unlock_should_work() {
}

#[test]
fn edit_fund_should_work() {
fn batch_migrate_should_work() {
new_test_ext().execute_with(|| {
assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get()));
assert_ok!(Salp::issue(Some(ALICE).into(), BRUCE, 3_000, 100));
assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000));
assert_ok!(Salp::edit(Some(ALICE).into(), 3_000, 1_000, 2, SlotLength::get() + 1, None));
let mut fund = Salp::funds(3_000).unwrap();
assert_eq!(fund.first_slot, 2);
assert_eq!(fund.status, FundStatus::Failed);

assert_ok!(Salp::edit(
Some(ALICE).into(),
3_000,
1_000,
2,
SlotLength::get() + 1,
Some(FundStatus::Ongoing),
Some(FundStatus::Ongoing)
));
fund = Salp::funds(3_000).unwrap();
assert_eq!(fund.status, FundStatus::Ongoing);
})
}
let to_migrate_fund = Salp::to_migrate_funds(3_000).unwrap();
assert_eq!(to_migrate_fund.first_slot, 2);

#[test]
fn batch_migrate_should_work() {
new_test_ext().execute_with(|| {
assert_ok!(Salp::create(Some(ALICE).into(), 3_000, 1_000, 1, SlotLength::get()));
assert_ok!(Salp::issue(Some(ALICE).into(), BRUCE, 3_000, 100));
assert_ok!(Salp::fund_fail(Some(ALICE).into(), 3_000));
let (_, vs_bond) = Salp::vsAssets(3000, 1, SlotLength::get());
assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 100);

assert_ok!(Salp::batch_migrate(Some(ALICE).into(), 3_000));

let migrated = Salp::to_migrate_funds(3_000);
assert!(migrated.is_none());

let fund = Salp::funds(3_000).unwrap();
assert_eq!(fund.status, FundStatus::Ongoing);
assert_eq!(fund.first_slot, 2);

#[allow(non_snake_case)]
let (_, vsBond) = Salp::vsAssets(3000, 1, SlotLength::get());
assert_eq!(Tokens::accounts(BRUCE, vsBond).reserved, 100);
assert_ok!(Salp::batch_migrate(Some(ALICE).into(), 3_000, 2, SlotLength::get() + 1));
let (_, vs_bond) = Salp::vsAssets(3000, 1, SlotLength::get());
assert_eq!(Tokens::accounts(BRUCE, vs_bond).reserved, 0);
let (_, vs_bond_new) = Salp::vsAssets(3000, 2, SlotLength::get() + 1);
assert_eq!(Tokens::accounts(BRUCE, vs_bond_new).reserved, 100);

assert_ok!(Salp::edit(
Some(ALICE).into(),
3_000,
1_000,
2,
SlotLength::get() + 1,
Some(FundStatus::Ongoing)
));
let fund = Salp::funds(3_000).unwrap();
assert_eq!(fund.first_slot, 2);
assert_eq!(fund.status, FundStatus::Ongoing);
})
}