Skip to content

Commit

Permalink
nmap
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszaaa committed Sep 21, 2023
1 parent 0fb361b commit 832ef12
Show file tree
Hide file tree
Showing 2 changed files with 300 additions and 17 deletions.
121 changes: 104 additions & 17 deletions pallets/proof-of-stake/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ pub use weights::WeightInfo;
#[derive(Eq, PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
pub enum ScheduleActivationKind {
ActivateKind(Option<ActivateKind>),
ActivatedLiquidity(TokenId)
ActivatedLiquidity(TokenId),
LiquidityMining,
}

type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
Expand Down Expand Up @@ -223,6 +224,32 @@ use super::*;
pub type TotalActivatedLiquidity3rdParty<T: Config> =
StorageMap<_, Twox64Concat, TokenId, BTreeMap<TokenId, u128>, ValueQuery>;


#[pallet::storage]
pub type ActivatedScheduleLiquidity<T> = StorageNMap<
_,
(
NMapKey<Twox64Concat, AccountIdOf<T>>,
NMapKey<Twox64Concat, TokenId>,
NMapKey<Twox64Concat, TokenId>
),
u128,
OptionQuery,
>;

#[pallet::storage]
pub type MaxActivatedLiquidity<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
AccountIdOf<T>,
Twox64Concat,
TokenId,
u128,
ValueQuery,
>;



#[pallet::call]
impl<T: Config> Pallet<T> {
/// Claims liquidity mining rewards
Expand Down Expand Up @@ -463,31 +490,45 @@ impl<T: Config> Pallet<T> {
),
Error::<T>::NotEnoughAssets
);
MaxActivatedLiquidity::<T>::mutate(user.clone(), liquidity_asset_id, |val| *val += amount);
},
ScheduleActivationKind::ActivatedLiquidity(token_id) => {
let already_activated_amount =
UserRewards3rdPartyInfo::<T>::get(user.clone(), (liquidity_asset_id, reward_token)).activated_amount;
let available_amount =
UserRewards3rdPartyInfo::<T>::get(user.clone(), (liquidity_asset_id, token_id)).activated_amount;
println!("already_activated_amount : {already_activated_amount:?}");
println!("available_amount : {available_amount:?}");

ensure!(
already_activated_amount + amount <= available_amount ,
Error::<T>::NotEnoughAssets
);
}
ScheduleActivationKind::LiquidityMining => {
let already_activated_amount =
UserRewards3rdPartyInfo::<T>::get(user.clone(), (liquidity_asset_id, reward_token)).activated_amount;
let available_amount =
RewardsInfo::<T>::get(user.clone(), liquidity_asset_id).activated_amount;
ensure!(
already_activated_amount + amount <= available_amount ,
Error::<T>::NotEnoughAssets
);
},
}

Self::set_liquidity_minting_checkpoint_3rdparty(user.clone(), liquidity_asset_id, amount, reward_token)?;

if let ScheduleActivationKind::ActivateKind(use_balance_from) = use_balance_from {
<T as Config>::ActivationReservesProvider::activate(
liquidity_asset_id,
&user,
amount,
use_balance_from,
)?;
match use_balance_from {
ScheduleActivationKind::ActivateKind(use_balance_from) => {
<T as Config>::ActivationReservesProvider::activate(
liquidity_asset_id,
&user,
amount,
use_balance_from,
)?;
},
ScheduleActivationKind::LiquidityMining => {
},
_ => {}

}

Pallet::<T>::deposit_event(Event::LiquidityActivated(user, liquidity_asset_id, amount));
Expand Down Expand Up @@ -724,10 +765,26 @@ impl<T: Config> Pallet<T> {
let rewards_info = calc
.activate_more(liquidity_assets_added)
.map_err(|err| Into::<Error<T>>::into(err))?;

UserRewards3rdPartyInfo::<T>::insert(user.clone(), (liquidity_asset_id, liquidity_assets_reward), rewards_info);
}

ActivatedScheduleLiquidity::<T>::try_mutate_exists(
(user.clone(), liquidity_asset_id, liquidity_assets_reward ),
|v|
{
match v {
Some(x) => {
v.as_mut().map(|a| *a += liquidity_assets_added);
},
None => {
*v = Some(liquidity_assets_added);
},
};
Ok::<(),Error<T>>(())
}
)?;

let x = ActivatedScheduleLiquidity::<T>::get( (user.clone(), liquidity_asset_id, liquidity_assets_reward));

TotalActivatedLiquidity3rdParty::<T>::mutate(liquidity_asset_id, |activations| {
activations
Expand Down Expand Up @@ -813,11 +870,41 @@ impl<T: Config> Pallet<T> {
.and_modify(|val| *val -= liquidity_assets_burned);
});

<T as Config>::ActivationReservesProvider::deactivate(
liquidity_asset_id,
&user,
liquidity_assets_burned,
);
ActivatedScheduleLiquidity::<T>::try_mutate_exists(
(user.clone(), liquidity_asset_id, reward_token),
|v|
{
v.and_then(|a| a.checked_sub(liquidity_assets_burned)
.and_then(|val| {
if val > 0 {
*v = Some(val);
}else{
*v = None;
}
Some(val)
})
).ok_or(Error::<T>::MathOverflow)
}
)?;



if let None = ActivatedScheduleLiquidity::<T>::iter_prefix_values( (user.clone(), liquidity_asset_id),
).next(){

let amount = MaxActivatedLiquidity::<T>::mutate(user.clone(), liquidity_asset_id, |val| {
let prev = *val;
*val = 0;
prev
});

<T as Config>::ActivationReservesProvider::deactivate(
liquidity_asset_id,
&user,
amount,
);
}
println!("WORLD");

Ok(())
}
Expand Down
196 changes: 196 additions & 0 deletions pallets/proof-of-stake/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1555,3 +1555,199 @@ fn deactivate_3rdparty_rewards() {
});
}


#[test]
#[serial]
fn claim_rewards_from_multiple_schedules_using_single_liquidity() {
new_test_ext().execute_with(|| {
System::set_block_number(1);
const LIQUIDITY_TOKEN : u32 = 5;
let valuation_mock = MockValuationApi::get_liquidity_asset_context();
valuation_mock.expect().return_const(Ok(LIQUIDITY_TOKEN));

assert_eq!(0, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(1, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(2, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(3, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(4, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(5, TokensOf::<Test>::create(&ALICE, 0).unwrap());

let first_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
let second_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
TokensOf::<Test>::mint(LIQUIDITY_TOKEN, &BOB, 100).unwrap();

let pair: (TokenId, TokenId) = (0u32.into(), 4u32.into());
let amount = 10_000u128;

ProofOfStake::update_pool_promotion(RuntimeOrigin::root(), LIQUIDITY_TOKEN, 1u8).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, first_token_id, amount, 10u32.into()).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, second_token_id, 2 * amount, 10u32.into()).unwrap();

ProofOfStake::activate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, first_token_id, None).unwrap();
ProofOfStake::activate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, second_token_id, Some(ScheduleActivationKind::ActivatedLiquidity(first_token_id))).unwrap();

assert_eq!(
ProofOfStake::calculate_rewards_amount_3rdparty(BOB, LIQUIDITY_TOKEN, first_token_id),
Ok(0)
);
assert_eq!(
ProofOfStake::calculate_rewards_amount_3rdparty(BOB, LIQUIDITY_TOKEN, second_token_id),
Ok(0)
);

roll_to_session(1);

assert_eq!(
ProofOfStake::calculate_rewards_amount_3rdparty(BOB, LIQUIDITY_TOKEN, first_token_id),
Ok(1000)
);
assert_eq!(
ProofOfStake::calculate_rewards_amount_3rdparty(BOB, LIQUIDITY_TOKEN, second_token_id),
Ok(2000)
);

});
}

#[test]
#[serial]
fn liquidity_minting_liquidity_can_be_resused() {
new_test_ext().execute_with(|| {
System::set_block_number(1);
const LIQUIDITY_TOKEN : u32 = 5;
let valuation_mock = MockValuationApi::get_liquidity_asset_context();
valuation_mock.expect().return_const(Ok(LIQUIDITY_TOKEN));

assert_eq!(0, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(1, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(2, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(3, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(4, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(5, TokensOf::<Test>::create(&ALICE, 0).unwrap());

let first_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
let second_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
TokensOf::<Test>::mint(LIQUIDITY_TOKEN, &BOB, 100).unwrap();

let pair: (TokenId, TokenId) = (0u32.into(), 4u32.into());
let amount = 10_000u128;

ProofOfStake::update_pool_promotion(RuntimeOrigin::root(), LIQUIDITY_TOKEN, 1u8).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, first_token_id, amount, 10u32.into()).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, second_token_id, 2 * amount, 10u32.into()).unwrap();

ProofOfStake::activate_liquidity(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, None).unwrap();
ProofOfStake::activate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, first_token_id, Some(ScheduleActivationKind::LiquidityMining)).unwrap();

roll_to_session(1);

assert_eq!(
ProofOfStake::calculate_rewards_amount(BOB, LIQUIDITY_TOKEN),
Ok(200)
);
assert_eq!(
ProofOfStake::calculate_rewards_amount_3rdparty(BOB, LIQUIDITY_TOKEN, first_token_id),
Ok(1000)
);

});
}

#[test]
#[serial]
fn when_liquidity_mining_is_reused_it_is_unlocked_properly() {
new_test_ext().execute_with(|| {
System::set_block_number(1);
const LIQUIDITY_TOKEN : u32 = 5;
let valuation_mock = MockValuationApi::get_liquidity_asset_context();
valuation_mock.expect().return_const(Ok(LIQUIDITY_TOKEN));

assert_eq!(0, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(1, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(2, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(3, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(4, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(5, TokensOf::<Test>::create(&ALICE, 0).unwrap());

let first_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
let second_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
TokensOf::<Test>::mint(LIQUIDITY_TOKEN, &BOB, 100).unwrap();

let pair: (TokenId, TokenId) = (0u32.into(), 4u32.into());
let amount = 10_000u128;

ProofOfStake::update_pool_promotion(RuntimeOrigin::root(), LIQUIDITY_TOKEN, 1u8).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, first_token_id, amount, 10u32.into()).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, second_token_id, 2 * amount, 10u32.into()).unwrap();

ProofOfStake::activate_liquidity(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, None).unwrap();
assert_err!(
TokensOf::<Test>::transfer(LIQUIDITY_TOKEN, &BOB, &CHARLIE, 100, ExistenceRequirement::AllowDeath),
orml_tokens::Error::<Test>::BalanceTooLow
);

ProofOfStake::activate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, first_token_id, Some(ScheduleActivationKind::LiquidityMining)).unwrap();

TokensOf::<Test>::mint(LIQUIDITY_TOKEN, &BOB, 100).unwrap();
ProofOfStake::activate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, first_token_id, None).unwrap();

ProofOfStake::deactivate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 200, first_token_id).unwrap();
assert_err!(
TokensOf::<Test>::transfer(LIQUIDITY_TOKEN, &BOB, &CHARLIE, 101, ExistenceRequirement::AllowDeath),
orml_tokens::Error::<Test>::BalanceTooLow
);

assert_ok!(
TokensOf::<Test>::transfer(LIQUIDITY_TOKEN, &BOB, &CHARLIE, 100, ExistenceRequirement::AllowDeath)
);
});
}

#[test]
#[serial]
fn liquidity_can_be_deactivated_when_all_reward_participation_were_deactivated() {
new_test_ext().execute_with(|| {
System::set_block_number(1);
const LIQUIDITY_TOKEN : u32 = 5;
let valuation_mock = MockValuationApi::get_liquidity_asset_context();
valuation_mock.expect().return_const(Ok(LIQUIDITY_TOKEN));

assert_eq!(0, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(1, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(2, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(3, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(4, TokensOf::<Test>::create(&ALICE, 0).unwrap());
assert_eq!(5, TokensOf::<Test>::create(&ALICE, 0).unwrap());

let first_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
let second_token_id = TokensOf::<Test>::create(&ALICE, MILLION).unwrap();
TokensOf::<Test>::mint(LIQUIDITY_TOKEN, &BOB, 100).unwrap();

let pair: (TokenId, TokenId) = (0u32.into(), 4u32.into());
let amount = 10_000u128;

ProofOfStake::update_pool_promotion(RuntimeOrigin::root(), LIQUIDITY_TOKEN, 1u8).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, first_token_id, amount, 10u32.into()).unwrap();
ProofOfStake::reward_pool(RuntimeOrigin::signed(ALICE), pair, second_token_id, amount, 10u32.into()).unwrap();
ProofOfStake::activate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, first_token_id, None).unwrap();
ProofOfStake::activate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, second_token_id, Some(ScheduleActivationKind::ActivatedLiquidity(first_token_id))).unwrap();

assert_err!(
TokensOf::<Test>::transfer(0, &BOB, &CHARLIE, 100, ExistenceRequirement::AllowDeath),
orml_tokens::Error::<Test>::BalanceTooLow
);
ProofOfStake::deactivate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, first_token_id).unwrap();
assert_err!(
TokensOf::<Test>::transfer(LIQUIDITY_TOKEN, &BOB, &CHARLIE, 100, ExistenceRequirement::AllowDeath),
orml_tokens::Error::<Test>::BalanceTooLow
);
ProofOfStake::deactivate_liquidity_for_rewards_schedule(RuntimeOrigin::signed(BOB), LIQUIDITY_TOKEN, 100, second_token_id).unwrap();

assert_ok!(
TokensOf::<Test>::transfer(LIQUIDITY_TOKEN, &BOB, &CHARLIE, 100, ExistenceRequirement::AllowDeath),
);


});
}

0 comments on commit 832ef12

Please sign in to comment.