Skip to content

Commit

Permalink
Add Farming functionality to Lottery (Manta-Network#1261)
Browse files Browse the repository at this point in the history
* compile init commit

Signed-off-by: Charles Ferrell <[email protected]>

* add withdraw logic

Signed-off-by: Charles Ferrell <[email protected]>

* fix withdrawals

Signed-off-by: Charles Ferrell <[email protected]>

* add enable farming toggle and add tests

Signed-off-by: Charles Ferrell <[email protected]>

* add to tests

Signed-off-by: Charles Ferrell <[email protected]>

* taplo fmt

Signed-off-by: Charles Ferrell <[email protected]>

* make farming params dynamic via governance

Signed-off-by: Charles Ferrell <[email protected]>

* tests and refactor lazy static out

Signed-off-by: Charles Ferrell <[email protected]>

* add to tests

Signed-off-by: Charles Ferrell <[email protected]>

* add tests for deposit and withdraw edge cases

Signed-off-by: Charles Ferrell <[email protected]>

* clippy

Signed-off-by: Charles Ferrell <[email protected]>

* fix tx diff test

Signed-off-by: Charles Ferrell <[email protected]>

---------

Signed-off-by: Charles Ferrell <[email protected]>
  • Loading branch information
ferrell-code authored Nov 22, 2023
1 parent 0d7b8b9 commit d7efd90
Show file tree
Hide file tree
Showing 12 changed files with 952 additions and 276 deletions.
7 changes: 6 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node/src/chain_specs/calamari.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ fn calamari_dev_genesis(
min_deposit: 5_000 * KMA,
min_withdraw: 5_000 * KMA,
gas_reserve: 10_000 * KMA,
farming_pool_params: Default::default(),
},
}
}
Expand Down
1 change: 1 addition & 0 deletions node/src/chain_specs/manta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ fn manta_devnet_genesis(genesis_collators: Vec<Collator>) -> GenesisConfig {
min_deposit: 500 * MANTA,
min_withdraw: 10 * MANTA,
gas_reserve: 1_000 * MANTA,
farming_pool_params: Default::default(),
},
parachain_info: manta_runtime::ParachainInfoConfig {
parachain_id: MANTA_PARACHAIN_ID.into(),
Expand Down
188 changes: 109 additions & 79 deletions pallets/farming/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,51 +430,7 @@ pub mod pallet {
) -> DispatchResult {
let exchanger = ensure_signed(origin)?;

let mut pool_info = Self::pool_infos(pool_id).ok_or(Error::<T>::PoolDoesNotExist)?;
ensure!(
PoolState::state_valid(Action::Deposit, pool_info.state),
Error::<T>::InvalidPoolState
);

if let PoolState::Charged = pool_info.state {
let n: BlockNumberFor<T> = frame_system::Pallet::<T>::block_number();
ensure!(
n >= pool_info.after_block_to_start,
Error::<T>::CanNotDeposit
);
}

// basic token proportion * add_value * token_proportion
// if basic token proportion and token_proportion both equals to 100%, then the final amount to transfer is equal to add_value
let native_amount = pool_info.basic_token.1.saturating_reciprocal_mul(add_value);
pool_info.tokens_proportion.iter().try_for_each(
|(token, proportion)| -> DispatchResult {
T::MultiCurrency::transfer(
*token,
&exchanger,
&pool_info.keeper,
*proportion * native_amount,
)
},
)?;
Self::add_share(&exchanger, pool_id, &mut pool_info, add_value);

if let Some((gauge_value, gauge_block)) = gauge_info {
Self::gauge_add(
&exchanger,
pool_info.gauge.ok_or(Error::<T>::GaugePoolNotExist)?,
gauge_value,
gauge_block,
)?;
}

Self::deposit_event(Event::Deposited {
who: exchanger,
pid: pool_id,
add_value,
gauge_info,
});
Ok(())
Self::deposit_farming(exchanger, pool_id, add_value, gauge_info)
}

/// `Withdraw` operation only remove share and get claim rewards, then update `withdraw_list` of user share info.
Expand All @@ -488,32 +444,7 @@ pub mod pallet {
) -> DispatchResult {
let exchanger = ensure_signed(origin)?;

let pool_info = Self::pool_infos(pool_id).ok_or(Error::<T>::PoolDoesNotExist)?;
ensure!(
PoolState::state_valid(Action::Withdraw, pool_info.state),
Error::<T>::InvalidPoolState
);

let share_info = Self::shares_and_withdrawn_rewards(pool_id, &exchanger)
.ok_or(Error::<T>::ShareInfoNotExists)?;
ensure!(
share_info.withdraw_list.len() < pool_info.withdraw_limit_count.into(),
Error::<T>::WithdrawLimitCountExceeded
);

Self::remove_share(
&exchanger,
pool_id,
remove_value,
pool_info.withdraw_limit_time,
)?;

Self::deposit_event(Event::Withdrawn {
who: exchanger,
pid: pool_id,
remove_value,
});
Ok(())
Self::withdraw_amount(exchanger, pool_id, remove_value)
}

/// `claim` operation can claim rewards and also un-stake if user share info has `withdraw_list`.
Expand Down Expand Up @@ -555,14 +486,7 @@ pub mod pallet {
pub fn withdraw_claim(origin: OriginFor<T>, pool_id: PoolId) -> DispatchResult {
let exchanger = ensure_signed(origin)?;

let pool_info = Self::pool_infos(pool_id).ok_or(Error::<T>::PoolDoesNotExist)?;
Self::process_withdraw_list(&exchanger, pool_id, &pool_info, false)?;

Self::deposit_event(Event::WithdrawClaimed {
who: exchanger,
pid: pool_id,
});
Ok(())
Self::withdraw_farming(exchanger, pool_id)
}

#[pallet::call_index(6)]
Expand Down Expand Up @@ -942,4 +866,110 @@ impl<T: Config> Pallet<T> {
.saturated_into();
total_reward_proportion
}

pub fn deposit_farming(
exchanger: T::AccountId,
pool_id: PoolId,
add_value: BalanceOf<T>,
gauge_info: Option<(BalanceOf<T>, BlockNumberFor<T>)>,
) -> DispatchResult {
let mut pool_info = Self::pool_infos(pool_id).ok_or(Error::<T>::PoolDoesNotExist)?;
ensure!(
PoolState::state_valid(Action::Deposit, pool_info.state),
Error::<T>::InvalidPoolState
);

if let PoolState::Charged = pool_info.state {
let n: BlockNumberFor<T> = frame_system::Pallet::<T>::block_number();
ensure!(
n >= pool_info.after_block_to_start,
Error::<T>::CanNotDeposit
);
}

// basic token proportion * add_value * token_proportion
// if basic token proportion and token_proportion both equals to 100%, then the final amount to transfer is equal to add_value
let native_amount = pool_info.basic_token.1.saturating_reciprocal_mul(add_value);
pool_info.tokens_proportion.iter().try_for_each(
|(token, proportion)| -> DispatchResult {
T::MultiCurrency::transfer(
*token,
&exchanger,
&pool_info.keeper,
*proportion * native_amount,
)
},
)?;
Self::add_share(&exchanger, pool_id, &mut pool_info, add_value);

if let Some((gauge_value, gauge_block)) = gauge_info {
Self::gauge_add(
&exchanger,
pool_info.gauge.ok_or(Error::<T>::GaugePoolNotExist)?,
gauge_value,
gauge_block,
)?;
}

Self::deposit_event(Event::Deposited {
who: exchanger,
pid: pool_id,
add_value,
gauge_info,
});
Ok(())
}

pub fn withdraw_farming(exchanger: T::AccountId, pool_id: PoolId) -> DispatchResult {
let pool_info = Self::pool_infos(pool_id).ok_or(Error::<T>::PoolDoesNotExist)?;
Self::process_withdraw_list(&exchanger, pool_id, &pool_info, false)?;

Self::deposit_event(Event::WithdrawClaimed {
who: exchanger,
pid: pool_id,
});
Ok(())
}

pub fn withdraw_amount(
exchanger: T::AccountId,
pool_id: PoolId,
remove_value: Option<BalanceOf<T>>,
) -> DispatchResult {
let pool_info = Self::pool_infos(pool_id).ok_or(Error::<T>::PoolDoesNotExist)?;
ensure!(
PoolState::state_valid(Action::Withdraw, pool_info.state),
Error::<T>::InvalidPoolState
);

let share_info = Self::shares_and_withdrawn_rewards(pool_id, &exchanger)
.ok_or(Error::<T>::ShareInfoNotExists)?;
ensure!(
share_info.withdraw_list.len() < pool_info.withdraw_limit_count.into(),
Error::<T>::WithdrawLimitCountExceeded
);

Self::remove_share(
&exchanger,
pool_id,
remove_value,
pool_info.withdraw_limit_time,
)?;

Self::deposit_event(Event::Withdrawn {
who: exchanger,
pid: pool_id,
remove_value,
});
Ok(())
}

pub fn withdraw_and_unstake(
exchanger: T::AccountId,
pool_id: PoolId,
remove_value: Option<BalanceOf<T>>,
) -> DispatchResult {
Self::withdraw_amount(exchanger.clone(), pool_id, remove_value)?;
Self::withdraw_farming(exchanger, pool_id)
}
}
9 changes: 8 additions & 1 deletion pallets/pallet-lottery/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ function_name = "0.3"
jsonrpsee = { version = "0.16.2", features = ["server", "macros"], optional = true }
log = { version = "0.4.0", default-features = false }
scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }
serde = { version = "1.0.136", default-features = false, optional = true }

# Substrate dependencies
frame-support = { git = 'https://github.com/paritytech/substrate.git', default-features = false, branch = "polkadot-v0.9.37" }
frame-system = { git = 'https://github.com/paritytech/substrate.git', default-features = false, branch = "polkadot-v0.9.37" }
orml-traits = { git = "https://github.com/manta-network/open-runtime-module-library.git", branch = "polkadot-v0.9.37", default-features = false }
sp-api = { git = 'https://github.com/paritytech/substrate.git', default-features = false, branch = "polkadot-v0.9.37" }
sp-arithmetic = { git = 'https://github.com/paritytech/substrate.git', default-features = false, branch = "polkadot-v0.9.37" }
sp-blockchain = { git = 'https://github.com/paritytech/substrate.git', default-features = false, branch = "polkadot-v0.9.37", optional = true }
Expand All @@ -28,6 +30,7 @@ sp-std = { git = 'https://github.com/paritytech/substrate.git', default-features

# Self dependencies
manta-primitives = { path = "../../primitives/manta", default-features = false }
pallet-farming = { path = '../farming', default-features = false }
pallet-parachain-staking = { path = '../parachain-staking', default-features = false }
runtime-common = { path = "../../runtime/common", default-features = false }
session-key-primitives = { path = '../../primitives/session-keys', default-features = false }
Expand All @@ -38,8 +41,9 @@ rand = { version = "0.8.5", default-features = false, optional = true }

[dev-dependencies]
calamari-runtime = { path = "../../runtime/calamari", default-features = false }
lazy_static = "1.4.0"
manta-collator-selection = { path = "../collator-selection", default-features = false }
pallet-asset-manager = { path = "../asset-manager", default-features = false }
pallet-assets = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" }
pallet-balances = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" }
pallet-preimage = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" }
pallet-randomness = { path = '../randomness', default-features = false }
Expand All @@ -48,6 +52,7 @@ pallet-transaction-payment = { git = "https://github.com/paritytech/substrate.gi
rand = "0.8"
similar-asserts = "1.1.0"
sp-staking = { git = 'https://github.com/paritytech/substrate.git', default-features = false, branch = "polkadot-v0.9.37" }
xcm = { git = "https://github.com/paritytech/polkadot.git", branch = "release-v0.9.37", default-features = false }

[features]
default = ["std"]
Expand Down Expand Up @@ -75,6 +80,8 @@ std = [
'frame-benchmarking/std',
"frame-support/std",
"frame-system/std",
"serde/std",
"pallet-farming/std",
]
try-runtime = [
"frame-support/try-runtime",
Expand Down
Loading

0 comments on commit d7efd90

Please sign in to comment.