Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix vtoken channel shares creation #1165

Merged
merged 10 commits into from
Jan 29, 2024
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
23 changes: 23 additions & 0 deletions pallets/channel-commission/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,29 @@ benchmarks! {
let block_num =BlockNumberFor::<T>::from(101u32);
}: {ChannelCommission::<T>::on_initialize(block_num);}

set_channel_vtoken_shares {
let origin = T::ControlOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
let vtoken_set = CurrencyId::VToken2(0);
let shares = Permill::from_percent(1);
let channel_id = 0;

// assume we have 60 channels at most
let x in 1 .. 60;
let channel_name = b"Bifrost".to_vec();
let receiver: T::AccountId = whitelisted_caller();

// set_commission_tokens
assert_ok!(ChannelCommission::<T>::set_commission_tokens(
origin.clone(),
vtoken_set, CurrencyId::Token2(0)
));

// register channels
for i in 0 .. x {
assert_ok!(ChannelCommission::<T>::register_channel(origin.clone(), channel_name.clone(), receiver.clone()));
}

}: _<T::RuntimeOrigin>(origin.clone(), channel_id, vtoken_set, shares)

impl_benchmark_test_suite!(ChannelCommission,crate::mock::ExtBuilder::default().build(),crate::mock::Runtime);
}
61 changes: 61 additions & 0 deletions pallets/channel-commission/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,11 @@ pub mod pallet {
// set the commission token
CommissionTokens::<T>::insert(vtoken, commission_token);

// set VtokenIssuanceSnapshots for the vtoken
let issuance = T::MultiCurrency::total_issuance(vtoken);
let zero_balance: BalanceOf<T> = Zero::zero();
VtokenIssuanceSnapshots::<T>::insert(vtoken, (zero_balance, issuance));

Self::deposit_event(Event::CommissionTokenSet {
vtoken,
commission_token: Some(commission_token),
Expand All @@ -485,6 +490,62 @@ pub mod pallet {
Self::settle_channel_commission(channel_id)?;
Ok(())
}

#[pallet::call_index(6)]
#[pallet::weight(T::WeightInfo::set_channel_vtoken_shares(Channels::<T>::iter().count() as u32))]
pub fn set_channel_vtoken_shares(
origin: OriginFor<T>,
channel_id: ChannelId,
vtoken: CurrencyId,
shares: Permill,
) -> DispatchResult {
T::ControlOrigin::ensure_origin(origin)?;

// check if the channel exists
ensure!(Channels::<T>::contains_key(channel_id), Error::<T>::ChannelNotExist);

// check if the vtoken exists
ensure!(
CommissionTokens::<T>::contains_key(vtoken),
Error::<T>::VtokenNotConfiguredForCommission
);

// get all channel_ids
let channel_ids: Vec<ChannelId> = Channels::<T>::iter_keys().collect();
// for each channel_id,get its vtoken share for the particular vtoken from the storage
// if channel_id equals the passed in channel_id, we use the passed in share instead of
// the storage one
let mut total_shares = Permill::zero();
for id in channel_ids {
let share = if id == channel_id {
shares
} else {
ChannelVtokenShares::<T>::get(id, vtoken)
};

// add up all the vtoken shares of all channels for this particular vtoken,
// but use the passed in share for the passed in channel_id
// if the sum of all shares is greater than 1, throw an error
let total_shares_op = total_shares.checked_add(&share);

if let Some(total_shares_new) = total_shares_op {
total_shares = total_shares_new
} else {
Err(Error::<T>::InvalidCommissionRate)?
};
}

// update the channel vtoken share
ChannelVtokenShares::<T>::insert(channel_id, vtoken, shares);

Self::deposit_event(Event::ChannelVtokenSharesUpdated {
channel_id,
vtoken,
share: shares,
});

Ok(())
}
}
}

Expand Down
102 changes: 101 additions & 1 deletion pallets/channel-commission/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

use crate::{mock::*, *};
use bifrost_primitives::{currency::KSM, BNC, VBNC, VKSM};
use frame_support::assert_ok;
use frame_support::{assert_noop, assert_ok};
use sp_runtime::AccountId32;

const CHANNEL_A_NAME: &[u8] = b"channel_a";
Expand Down Expand Up @@ -482,3 +482,103 @@ fn channel_commission_distribution_with_net_mint_negative_should_work() {
assert_eq!(bifrost_commission_balance_after, 100 - 6);
});
}

#[test]
fn set_channel_vtoken_shares_should_work() {
ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| {
setup();

// assure Channel A has no 0 percent in ChannelVtokenShares in VKSM
assert_eq!(ChannelVtokenShares::<Runtime>::get(0, VKSM), Permill::from_percent(0));

// set channel A's vtoken share in VKSM to 50%
assert_ok!(ChannelCommission::set_channel_vtoken_shares(
RuntimeOrigin::signed(ALICE),
0,
VKSM,
Permill::from_percent(50),
));

assert_eq!(ChannelVtokenShares::<Runtime>::get(0, VKSM), Permill::from_percent(50));

// set channel B's vtoken share in VKSM to 90%, it should fail because the sum of all shares
// should be less than or equal to 100%
assert_noop!(
ChannelCommission::set_channel_vtoken_shares(
RuntimeOrigin::signed(ALICE),
1,
VKSM,
Permill::from_percent(90),
),
Error::<Runtime>::InvalidCommissionRate
);

// set channel B's vtoken share in VKSM to 30%, it should be ok now
assert_ok!(ChannelCommission::set_channel_vtoken_shares(
RuntimeOrigin::signed(ALICE),
1,
VKSM,
Permill::from_percent(30),
));

assert_eq!(ChannelVtokenShares::<Runtime>::get(1, VKSM), Permill::from_percent(30));
});
}

// register a new channel base on some existing channels, and mint some tokens to see whether the
// shares of existing channels are updated correctly.s
#[test]
fn register_a_new_channel_and_mint_should_update_shares_and_get_claimable_tokens() {
ExtBuilder::default().one_hundred_for_alice_n_bob().build().execute_with(|| {
let commission_account: AccountId =
<Runtime as crate::Config>::CommissionPalletId::get().into_account_truncating();

// set the block number to 35
System::set_block_number(35);

// we have registered channel A and channel B for 0 shares for VKSM
setup();

// VtokenIssuanceSnapshots, set VKSM old total issuance to 10000. newly minted
// VKSM is 1000
VtokenIssuanceSnapshots::<Runtime>::insert(VKSM, (9000, 10000));

// PeriodVtokenTotalMint
PeriodVtokenTotalMint::<Runtime>::insert(VKSM, (10000, 2000));

// PeriodVtokenTotalRedeem
PeriodVtokenTotalRedeem::<Runtime>::insert(VKSM, (0, 1000));

// PeriodChannelVtokenMint. Channel A mint 1000 VKSM, Channel B mint 1000 VKSM.
PeriodChannelVtokenMint::<Runtime>::insert(0, VKSM, (2000, 500));
PeriodChannelVtokenMint::<Runtime>::insert(1, VKSM, (2000, 100));

// set vksm token issuance to 11000
let _ = Currencies::update_balance(
RuntimeOrigin::root(),
commission_account.clone(),
VKSM,
11000,
);

// set ksm token issuance to 11000
let _ = Currencies::update_balance(
RuntimeOrigin::root(),
commission_account.clone(),
KSM,
11000,
);

// set block number to 100
run_to_block(100);
run_to_block(101);

let channel_a_new_net_mint: u32 = 500 * 1000 / 2000;

let channel_a_new_percentage =
Permill::from_rational_with_rounding(channel_a_new_net_mint, 11000u32, Rounding::Down)
.unwrap();
// check channel A vtoken share after being cleared
assert_eq!(ChannelVtokenShares::<Runtime>::get(0, VKSM), channel_a_new_percentage);
});
}
11 changes: 11 additions & 0 deletions pallets/channel-commission/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub trait WeightInfo {
fn set_commission_tokens() -> Weight;
fn claim_commissions() -> Weight;
fn on_initialize(x: u32, ) -> Weight;
fn set_channel_vtoken_shares(x: u32,) -> Weight;
}

// For backwards compatibility and tests
Expand Down Expand Up @@ -169,4 +170,14 @@ impl WeightInfo for () {
.saturating_add(Weight::from_parts(58_153, 0).saturating_mul(x.into()))
.saturating_add(RocksDbWeight::get().reads(1_u64))
}

fn set_channel_vtoken_shares(x: u32, ) -> Weight {
Weight::from_parts(43_239_575, 3597)
.saturating_add(Weight::from_parts(5_355_920, 0).saturating_mul(x.into()))
.saturating_add(RocksDbWeight::get().reads(2_u64))
.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(x.into())))
.saturating_add(RocksDbWeight::get().writes(2_u64))
.saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(x.into())))
.saturating_add(Weight::from_parts(0, 2499).saturating_mul(x.into()))
}
}
34 changes: 17 additions & 17 deletions runtime/bifrost-kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1786,22 +1786,22 @@ impl leverage_staking::Config for Runtime {
type CurrencyIdConversion = AssetIdMaps<Runtime>;
}

// parameter_types! {
// pub const ClearingDuration: u32 = prod_or_fast!(7 * DAYS, 10 * MINUTES);
// pub const NameLengthLimit: u32 = 20;
// pub BifrostCommissionReceiver: AccountId = TreasuryPalletId::get().into_account_truncating();
// }
//
// impl bifrost_channel_commission::Config for Runtime {
// type RuntimeEvent = RuntimeEvent;
// type MultiCurrency = Currencies;
// type ControlOrigin = EitherOfDiverse<CoreAdminOrCouncil, LiquidStaking>;
// type CommissionPalletId = CommissionPalletId;
// type BifrostCommissionReceiver = BifrostCommissionReceiver;
// type WeightInfo = weights::bifrost_channel_commission::BifrostWeight<Runtime>;
// type ClearingDuration = ClearingDuration;
// type NameLengthLimit = NameLengthLimit;
// }
parameter_types! {
pub const ClearingDuration: u32 = prod_or_fast!(7 * DAYS, 10 * MINUTES);
pub const NameLengthLimit: u32 = 20;
pub BifrostCommissionReceiver: AccountId = TreasuryPalletId::get().into_account_truncating();
}

impl bifrost_channel_commission::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type MultiCurrency = Currencies;
type ControlOrigin = EitherOfDiverse<CoreAdminOrCouncil, LiquidStaking>;
type CommissionPalletId = CommissionPalletId;
type BifrostCommissionReceiver = BifrostCommissionReceiver;
type WeightInfo = weights::bifrost_channel_commission::BifrostWeight<Runtime>;
type ClearingDuration = ClearingDuration;
type NameLengthLimit = NameLengthLimit;
}

// Below is the implementation of tokens manipulation functions other than native token.
pub struct LocalAssetAdaptor<Local>(PhantomData<Local>);
Expand Down Expand Up @@ -1989,7 +1989,7 @@ construct_runtime! {
Oracle: orml_oracle::<Instance1> = 133,
OracleMembership: pallet_membership::<Instance3> = 134,
LeverageStaking: leverage_staking = 135,
// ChannelCommission: bifrost_channel_commission = 136,
ChannelCommission: bifrost_channel_commission = 136,
}
}

Expand Down
10 changes: 10 additions & 0 deletions runtime/bifrost-kusama/src/weights/bifrost_channel_commission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,14 @@ impl<T: frame_system::Config> bifrost_channel_commission::WeightInfo for Bifrost
.saturating_add(Weight::from_parts(69_114, 0).saturating_mul(x.into()))
.saturating_add(T::DbWeight::get().reads(1))
}

fn set_channel_vtoken_shares(x: u32, ) -> Weight {
Weight::from_parts(43_239_575, 3597)
.saturating_add(Weight::from_parts(5_355_920, 0).saturating_mul(x.into()))
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into())))
.saturating_add(T::DbWeight::get().writes(2_u64))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into())))
.saturating_add(Weight::from_parts(0, 2499).saturating_mul(x.into()))
}
}
34 changes: 17 additions & 17 deletions runtime/bifrost-polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,22 +1594,22 @@ impl leverage_staking::Config for Runtime {
type CurrencyIdConversion = AssetIdMaps<Runtime>;
}

// parameter_types! {
// pub const ClearingDuration: u32 = prod_or_fast!(7 * DAYS, 10 * MINUTES);
// pub const NameLengthLimit: u32 = 20;
// pub BifrostCommissionReceiver: AccountId = TreasuryPalletId::get().into_account_truncating();
// }
//
// impl bifrost_channel_commission::Config for Runtime {
// type RuntimeEvent = RuntimeEvent;
// type MultiCurrency = Currencies;
// type ControlOrigin = EitherOfDiverse<CoreAdminOrCouncil, LiquidStaking>;
// type CommissionPalletId = CommissionPalletId;
// type BifrostCommissionReceiver = BifrostCommissionReceiver;
// type WeightInfo = weights::bifrost_channel_commission::BifrostWeight<Runtime>;
// type ClearingDuration = ClearingDuration;
// type NameLengthLimit = NameLengthLimit;
// }
parameter_types! {
pub const ClearingDuration: u32 = prod_or_fast!(7 * DAYS, 10 * MINUTES);
pub const NameLengthLimit: u32 = 20;
pub BifrostCommissionReceiver: AccountId = TreasuryPalletId::get().into_account_truncating();
}

impl bifrost_channel_commission::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type MultiCurrency = Currencies;
type ControlOrigin = EitherOfDiverse<CoreAdminOrCouncil, LiquidStaking>;
type CommissionPalletId = CommissionPalletId;
type BifrostCommissionReceiver = BifrostCommissionReceiver;
type WeightInfo = weights::bifrost_channel_commission::BifrostWeight<Runtime>;
type ClearingDuration = ClearingDuration;
type NameLengthLimit = NameLengthLimit;
}

// Below is the implementation of tokens manipulation functions other than native token.
pub struct LocalAssetAdaptor<Local>(PhantomData<Local>);
Expand Down Expand Up @@ -1794,7 +1794,7 @@ construct_runtime! {
Oracle: orml_oracle::<Instance1> = 133,
OracleMembership: pallet_membership::<Instance3> = 134,
LeverageStaking: leverage_staking = 135,
// ChannelCommission: bifrost_channel_commission = 136,
ChannelCommission: bifrost_channel_commission = 136,
}
}

Expand Down
10 changes: 10 additions & 0 deletions runtime/bifrost-polkadot/src/weights/bifrost_channel_commission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,14 @@ impl<T: frame_system::Config> bifrost_channel_commission::WeightInfo for Bifrost
.saturating_add(Weight::from_parts(220_865, 0).saturating_mul(x.into()))
.saturating_add(T::DbWeight::get().reads(1))
}

fn set_channel_vtoken_shares(x: u32, ) -> Weight {
Weight::from_parts(43_239_575, 3597)
.saturating_add(Weight::from_parts(5_355_920, 0).saturating_mul(x.into()))
.saturating_add(T::DbWeight::get().reads(2_u64))
.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into())))
.saturating_add(T::DbWeight::get().writes(2_u64))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into())))
.saturating_add(Weight::from_parts(0, 2499).saturating_mul(x.into()))
}
}
Loading