-
Notifications
You must be signed in to change notification settings - Fork 46
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
farm position first audit fixes #772
Changes from 1 commit
4b4e0b7
c044821
16576f1
3fc935a
be142a3
a77b760
3fe300e
37c9ebc
9859e47
d9fd841
65930ce
ee6644c
1e9ec92
bbff637
c609e42
8ac9c19
4303c0c
767f452
8100d57
aba2e4e
1d92432
494b301
772779a
d790945
0ee2b42
4262fa1
a6e3e00
36be963
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,11 +19,20 @@ pub const DEFAULT_NFT_DEPOSIT_MAX_LEN: usize = 10; | |
PartialEq, | ||
Debug, | ||
)] | ||
pub struct UserTotalFarmPositionStruct<M: ManagedTypeApi> { | ||
pub struct UserTotalFarmPosition<M: ManagedTypeApi> { | ||
pub total_farm_position: BigUint<M>, | ||
pub allow_external_claim_boosted_rewards: bool, | ||
} | ||
|
||
impl<M: ManagedTypeApi> Default for UserTotalFarmPosition<M> { | ||
fn default() -> Self { | ||
Self { | ||
total_farm_position: BigUint::zero(), | ||
allow_external_claim_boosted_rewards: false, | ||
} | ||
} | ||
} | ||
|
||
#[multiversx_sc::module] | ||
pub trait ConfigModule: pausable::PausableModule + permissions_module::PermissionsModule { | ||
#[inline] | ||
|
@@ -32,17 +41,36 @@ pub trait ConfigModule: pausable::PausableModule + permissions_module::Permissio | |
state == State::Active | ||
} | ||
|
||
fn get_user_total_farm_position_struct( | ||
fn get_user_total_farm_position( | ||
&self, | ||
user: &ManagedAddress, | ||
) -> UserTotalFarmPositionStruct<Self::Api> { | ||
self.user_total_farm_position(user) | ||
.set_if_empty(UserTotalFarmPositionStruct { | ||
total_farm_position: BigUint::zero(), | ||
allow_external_claim_boosted_rewards: false, | ||
}); | ||
) -> UserTotalFarmPosition<Self::Api> { | ||
let user_total_farm_position_mapper = self.user_total_farm_position(user); | ||
if user_total_farm_position_mapper.is_empty() { | ||
UserTotalFarmPosition::default() | ||
} else { | ||
user_total_farm_position_mapper.get() | ||
} | ||
} | ||
|
||
self.user_total_farm_position(user).get() | ||
#[endpoint(allowExternalClaimBoostedRewards)] | ||
fn allow_external_claim_boosted_rewards(&self, allow_external_claim: bool) { | ||
let caller = self.blockchain().get_caller(); | ||
let user_total_farm_position_mapper = self.user_total_farm_position(&caller); | ||
if user_total_farm_position_mapper.is_empty() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is no need for this if. Actually the user must have a farm position before making this allow call. |
||
require!( | ||
allow_external_claim, | ||
"Can only set to true if there is no farm position" | ||
); | ||
let mut new_user_farm_position: UserTotalFarmPosition<Self::Api> = | ||
UserTotalFarmPosition::default(); | ||
new_user_farm_position.allow_external_claim_boosted_rewards = allow_external_claim; | ||
} else { | ||
user_total_farm_position_mapper.update(|user_total_farm_position| { | ||
user_total_farm_position.allow_external_claim_boosted_rewards = | ||
allow_external_claim; | ||
}); | ||
} | ||
} | ||
|
||
#[view(getFarmingTokenId)] | ||
|
@@ -73,5 +101,5 @@ pub trait ConfigModule: pausable::PausableModule + permissions_module::Permissio | |
fn user_total_farm_position( | ||
&self, | ||
user: &ManagedAddress, | ||
) -> SingleValueMapper<UserTotalFarmPositionStruct<Self::Api>>; | ||
) -> SingleValueMapper<UserTotalFarmPosition<Self::Api>>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -210,8 +210,10 @@ pub trait FarmContract { | |
} | ||
} | ||
|
||
let user_total_farm_position_struct = sc.get_user_total_farm_position_struct(user); | ||
if user_total_farm_position_struct.total_farm_position == BigUint::zero() { | ||
let user_total_farm_position = sc.get_user_total_farm_position(user); | ||
if user_total_farm_position.total_farm_position == BigUint::zero() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for this if. Make farm_position_increase += farm_position.amount if the farm_position is old. Also Do not decrease_user_farm_position for old_farm_positions. |
||
&& total_farm_position > 0 | ||
{ | ||
Self::increase_user_farm_position(sc, user, &total_farm_position); | ||
} else if farm_position_increase > 0 { | ||
Self::increase_user_farm_position(sc, user, &farm_position_increase); | ||
|
@@ -224,10 +226,10 @@ pub trait FarmContract { | |
user: &ManagedAddress<<Self::FarmSc as ContractBase>::Api>, | ||
increase_farm_position_amount: &BigUint<<Self::FarmSc as ContractBase>::Api>, | ||
) { | ||
let mut user_total_farm_position = sc.get_user_total_farm_position(user); | ||
user_total_farm_position.total_farm_position += increase_farm_position_amount; | ||
sc.user_total_farm_position(user) | ||
.update(|user_farm_position_struct| { | ||
user_farm_position_struct.total_farm_position += increase_farm_position_amount | ||
}); | ||
.set(user_total_farm_position); | ||
} | ||
|
||
fn decrease_user_farm_position( | ||
|
@@ -238,17 +240,24 @@ pub trait FarmContract { | |
let token_attributes: FarmTokenAttributes<<Self::FarmSc as ContractBase>::Api> = | ||
farm_token_mapper.get_token_attributes(farm_position.token_nonce); | ||
|
||
sc.user_total_farm_position(&token_attributes.original_owner) | ||
.update(|user_farm_position_struct| { | ||
let mut user_total_farm_position = | ||
user_farm_position_struct.total_farm_position.clone(); | ||
if user_total_farm_position > farm_position.amount { | ||
user_total_farm_position -= &farm_position.amount; | ||
} else { | ||
user_total_farm_position = BigUint::zero(); | ||
} | ||
user_farm_position_struct.total_farm_position = user_total_farm_position; | ||
}); | ||
let mut user_total_farm_position = | ||
sc.get_user_total_farm_position(&token_attributes.original_owner); | ||
|
||
if user_total_farm_position.total_farm_position > farm_position.amount { | ||
user_total_farm_position.total_farm_position -= &farm_position.amount; | ||
} else { | ||
user_total_farm_position.total_farm_position = BigUint::zero(); | ||
} | ||
|
||
if user_total_farm_position.total_farm_position == 0 | ||
&& user_total_farm_position.allow_external_claim_boosted_rewards == false | ||
{ | ||
sc.user_total_farm_position(&token_attributes.original_owner) | ||
.clear(); | ||
} else { | ||
sc.user_total_farm_position(&token_attributes.original_owner) | ||
.set(user_total_farm_position); | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ use core::marker::PhantomData; | |
use mergeable::Mergeable; | ||
|
||
use farm::{ | ||
base_functions::{BaseFunctionsModule, ClaimRewardsResultType, Wrapper}, | ||
base_functions::{BaseFunctionsModule, ClaimRewardsResultType, DoubleMultiPayment, Wrapper}, | ||
exit_penalty::{ | ||
DEFAULT_BURN_GAS_LIMIT, DEFAULT_MINUMUM_FARMING_EPOCHS, DEFAULT_PENALTY_PERCENT, | ||
}, | ||
|
@@ -34,8 +34,6 @@ pub trait Farm: | |
+ multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule | ||
+ farm::base_functions::BaseFunctionsModule | ||
+ farm::exit_penalty::ExitPenaltyModule | ||
+ farm::progress_update::ProgressUpdateModule | ||
+ farm::claim_boost_only::ClaimBoostOnlyModule | ||
+ farm_base_impl::base_farm_init::BaseFarmInitModule | ||
+ farm_base_impl::base_farm_validation::BaseFarmValidationModule | ||
+ farm_base_impl::enter_farm::BaseEnterFarmModule | ||
|
@@ -89,27 +87,24 @@ pub trait Farm: | |
let caller = self.blockchain().get_caller(); | ||
let orig_caller = self.get_orig_caller_from_opt(&caller, opt_orig_caller); | ||
|
||
let payments = self.get_non_empty_payments(); | ||
let first_additional_payment_index = 1; | ||
let boosted_rewards = match payments.try_get(first_additional_payment_index) { | ||
Some(p) => { | ||
let unlocked_rewards = self.claim_only_boosted_payment(&orig_caller, &p); | ||
self.send_to_lock_contract_non_zero( | ||
unlocked_rewards.token_identifier, | ||
unlocked_rewards.amount, | ||
caller.clone(), | ||
orig_caller.clone(), | ||
) | ||
} | ||
None => EsdtTokenPayment::new(self.reward_token_id().get(), 0, BigUint::zero()), | ||
let boosted_rewards = self.claim_only_boosted_payment(&orig_caller); | ||
let boosted_rewards_payment = if boosted_rewards > 0 { | ||
self.send_to_lock_contract_non_zero( | ||
self.reward_token_id().get(), | ||
boosted_rewards, | ||
caller.clone(), | ||
orig_caller.clone(), | ||
) | ||
} else { | ||
EsdtTokenPayment::new(self.reward_token_id().get(), 0, BigUint::zero()) | ||
}; | ||
|
||
let new_farm_token = self.enter_farm::<NoMintWrapper<Self>>(orig_caller.clone()); | ||
self.send_payment_non_zero(&caller, &new_farm_token); | ||
|
||
self.update_energy_and_progress(&orig_caller); | ||
|
||
(new_farm_token, boosted_rewards).into() | ||
(new_farm_token, boosted_rewards_payment).into() | ||
} | ||
|
||
#[payable("*")] | ||
|
@@ -163,7 +158,10 @@ pub trait Farm: | |
"Exit amount is bigger than the payment amount" | ||
); | ||
|
||
let boosted_rewards_full_position = self.claim_only_boosted_payment(&orig_caller, &payment); | ||
let boosted_rewards = self.claim_only_boosted_payment(&orig_caller); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Call migrate_old_farm_position here as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. claim rewards and make a new position for the whole payment. Do the same on farm-staking. |
||
let boosted_rewards_full_position = | ||
EsdtTokenPayment::new(self.reward_token_id().get(), 0, boosted_rewards); | ||
|
||
let remaining_farm_payment = EsdtTokenPayment::new( | ||
payment.token_identifier.clone(), | ||
payment.token_nonce, | ||
|
@@ -186,7 +184,7 @@ pub trait Farm: | |
orig_caller.clone(), | ||
); | ||
|
||
self.clear_user_energy_if_needed(&orig_caller, &remaining_farm_payment.amount); | ||
self.clear_user_energy_if_needed(&orig_caller); | ||
|
||
( | ||
exit_farm_result.farming_tokens, | ||
|
@@ -196,41 +194,57 @@ pub trait Farm: | |
.into() | ||
} | ||
|
||
#[view(calculateRewardsForGivenPosition)] | ||
fn calculate_rewards_for_given_position( | ||
&self, | ||
user: ManagedAddress, | ||
farm_token_amount: BigUint, | ||
attributes: FarmTokenAttributes<Self::Api>, | ||
) -> BigUint { | ||
self.require_queried(); | ||
|
||
let mut storage_cache = StorageCache::new(self); | ||
NoMintWrapper::<Self>::generate_aggregated_rewards(self, &mut storage_cache); | ||
|
||
NoMintWrapper::<Self>::calculate_rewards( | ||
self, | ||
&user, | ||
&farm_token_amount, | ||
&attributes, | ||
&storage_cache, | ||
) | ||
} | ||
|
||
#[payable("*")] | ||
#[endpoint(mergeFarmTokens)] | ||
fn merge_farm_tokens_endpoint( | ||
&self, | ||
opt_orig_caller: OptionalValue<ManagedAddress>, | ||
) -> EsdtTokenPayment<Self::Api> { | ||
) -> DoubleMultiPayment<Self::Api> { | ||
let caller = self.blockchain().get_caller(); | ||
let orig_caller = self.get_orig_caller_from_opt(&caller, opt_orig_caller); | ||
self.check_claim_progress_for_merge(&orig_caller); | ||
|
||
let boosted_rewards = self.claim_only_boosted_payment(&orig_caller); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the payments are old tokens - we need to increase the total_position of the user. If they are new tokens we have to check and change total_positions if original_user != caller. I think we could make a function called = adjust_total_position - which gets the payments and computes the total_position for the user and decreases for original_user. We do not need to claim_boosted_rewards. |
||
|
||
let merged_farm_token = self.merge_farm_tokens::<NoMintWrapper<Self>>(); | ||
self.send_payment_non_zero(&caller, &merged_farm_token); | ||
|
||
merged_farm_token | ||
let locked_rewards_payment = self.send_to_lock_contract_non_zero( | ||
self.reward_token_id().get(), | ||
boosted_rewards, | ||
caller, | ||
orig_caller.clone(), | ||
); | ||
|
||
(merged_farm_token, locked_rewards_payment).into() | ||
} | ||
|
||
#[endpoint(claimBoostedRewards)] | ||
fn claim_boosted_rewards( | ||
&self, | ||
opt_user: OptionalValue<ManagedAddress>, | ||
) -> EsdtTokenPayment<Self::Api> { | ||
let caller = self.blockchain().get_caller(); | ||
let user = match &opt_user { | ||
OptionalValue::Some(user) => user, | ||
OptionalValue::None => &caller, | ||
}; | ||
let user_total_farm_position = self.get_user_total_farm_position(user); | ||
if user != &caller { | ||
require!( | ||
user_total_farm_position.allow_external_claim_boosted_rewards, | ||
"Cannot claim rewards for this address" | ||
); | ||
} | ||
|
||
let boosted_rewards = self.claim_only_boosted_payment(&user); | ||
let locked_rewards_payment = self.send_to_lock_contract_non_zero( | ||
self.reward_token_id().get(), | ||
boosted_rewards, | ||
caller.clone(), | ||
user.clone(), | ||
); | ||
|
||
locked_rewards_payment | ||
} | ||
|
||
#[endpoint(startProduceRewards)] | ||
|
@@ -251,6 +265,27 @@ pub trait Farm: | |
self.set_per_block_rewards::<NoMintWrapper<Self>>(per_block_amount); | ||
} | ||
|
||
#[view(calculateRewardsForGivenPosition)] | ||
fn calculate_rewards_for_given_position( | ||
&self, | ||
user: ManagedAddress, | ||
farm_token_amount: BigUint, | ||
attributes: FarmTokenAttributes<Self::Api>, | ||
) -> BigUint { | ||
self.require_queried(); | ||
|
||
let mut storage_cache = StorageCache::new(self); | ||
NoMintWrapper::<Self>::generate_aggregated_rewards(self, &mut storage_cache); | ||
|
||
NoMintWrapper::<Self>::calculate_rewards( | ||
self, | ||
&user, | ||
&farm_token_amount, | ||
&attributes, | ||
&storage_cache, | ||
) | ||
} | ||
|
||
fn send_to_lock_contract_non_zero( | ||
&self, | ||
token_id: TokenIdentifier, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need a new bool here: migrated. And to keep that even if total_farm_position gets to 0 again. Or to not delete claimProgressWeek from user.