diff --git a/Cargo.lock b/Cargo.lock index 4ac1016f6..42951acbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -523,9 +523,11 @@ dependencies = [ "multiversx-sc-modules", "multiversx-sc-scenario", "num-bigint", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -584,9 +586,11 @@ dependencies = [ "multiversx-sc-modules", "multiversx-sc-scenario", "num-bigint", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -629,6 +633,7 @@ dependencies = [ "pair", "pausable", "permissions-hub", + "permissions_hub_module", "rewards", "sc_whitelist_module", "simple-lock", @@ -768,8 +773,10 @@ dependencies = [ "multiversx-sc-modules", "multiversx-sc-scenario", "num-bigint", + "original_owner_helper", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -883,6 +890,7 @@ dependencies = [ "rewards", "router", "simple-lock", + "timestamp-oracle", ] [[package]] @@ -1365,6 +1373,14 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -1433,6 +1449,7 @@ dependencies = [ "multiversx-sc-scenario", "pair", "pausable", + "timestamp-oracle", ] [[package]] @@ -1460,6 +1477,14 @@ dependencies = [ "permissions-hub", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" @@ -1558,13 +1583,16 @@ dependencies = [ name = "proxy-deployer" version = "0.0.0" dependencies = [ - "config", - "farm", + "common_structs", + "farm-boosted-yields", + "farm-staking", "farm_token", "multiversx-sc", "multiversx-sc-scenario", "num-bigint", "pausable", + "permissions_module", + "timestamp-oracle", ] [[package]] diff --git a/common/modules/farm/contexts/src/storage_cache.rs b/common/modules/farm/contexts/src/storage_cache.rs index 76f4cfc1d..e48e5fc85 100644 --- a/common/modules/farm/contexts/src/storage_cache.rs +++ b/common/modules/farm/contexts/src/storage_cache.rs @@ -41,7 +41,7 @@ impl<'a, C: FarmContracTraitBounds> StorageCache<'a, C> { } } -impl<'a, C: FarmContracTraitBounds> Drop for StorageCache<'a, C> { +impl Drop for StorageCache<'_, C> { fn drop(&mut self) { // commit changes to storage for the mutable fields self.sc_ref.reward_reserve().set(&self.reward_reserve); diff --git a/common/modules/farm/farm_base_impl/src/base_farm_init.rs b/common/modules/farm/farm_base_impl/src/base_farm_init.rs index 700057a3e..5387f57b4 100644 --- a/common/modules/farm/farm_base_impl/src/base_farm_init.rs +++ b/common/modules/farm/farm_base_impl/src/base_farm_init.rs @@ -50,5 +50,7 @@ pub trait BaseFarmInitModule: self.add_permissions(caller, Permissions::OWNER | Permissions::PAUSE); self.add_permissions_for_all(admins, Permissions::ADMIN); }; + + self.pause(); } } diff --git a/common/modules/original_owner_helper/Cargo.toml b/common/modules/original_owner_helper/Cargo.toml new file mode 100644 index 000000000..21fa393dc --- /dev/null +++ b/common/modules/original_owner_helper/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "original_owner_helper" +version = "0.0.0" +authors = ["MultiversX "] +edition = "2021" + +[lib] +path = "src/lib.rs" + +[dependencies.multiversx-sc] +version = "=0.53.2" +features = ["esdt-token-payment-legacy-decode"] + +[dependencies.common_structs] +path = "../../common_structs" diff --git a/common/modules/original_owner_helper/src/lib.rs b/common/modules/original_owner_helper/src/lib.rs new file mode 100644 index 000000000..3f5126929 --- /dev/null +++ b/common/modules/original_owner_helper/src/lib.rs @@ -0,0 +1,62 @@ +#![no_std] + +multiversx_sc::imports!(); + +use common_structs::{FarmToken, PaymentsVec}; + +#[multiversx_sc::module] +pub trait OriginalOwnerHelperModule { + fn check_and_return_original_owner + TopDecode>( + &self, + payments: &PaymentsVec, + farm_token_mapper: &NonFungibleTokenMapper, + ) -> ManagedAddress { + let mut original_owner = ManagedAddress::zero(); + for payment in payments.iter() { + let attributes: T = farm_token_mapper.get_token_attributes(payment.token_nonce); + let payment_original_owner = attributes.get_original_owner(); + + if original_owner.is_zero() { + original_owner = payment_original_owner; + } else { + require!( + original_owner == payment_original_owner, + "All position must have the same original owner" + ); + } + } + + require!( + !original_owner.is_zero(), + "Original owner could not be identified" + ); + + original_owner + } + + fn check_additional_payments_original_owner + TopDecode>( + &self, + user: &ManagedAddress, + payments: &PaymentsVec, + farm_token_mapper: &NonFungibleTokenMapper, + ) { + if payments.len() == 1 { + return; + } + + let farm_token_id = farm_token_mapper.get_token_id(); + for payment in payments.into_iter() { + if payment.token_identifier != farm_token_id { + continue; + } + + let attributes: T = farm_token_mapper.get_token_attributes(payment.token_nonce); + let payment_original_owner = attributes.get_original_owner(); + + require!( + user == &payment_original_owner, + "Provided address is not the same as the original owner" + ); + } + } +} diff --git a/common/modules/permissions_hub_module/Cargo.toml b/common/modules/permissions_hub_module/Cargo.toml new file mode 100644 index 000000000..503fe9d60 --- /dev/null +++ b/common/modules/permissions_hub_module/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "permissions_hub_module" +version = "0.0.0" +authors = ["MultiversX "] +edition = "2021" + +[lib] +path = "src/permissions_hub_module.rs" + +[dependencies.permissions-hub] +path = "../../../dex/permissions-hub" + +[dependencies.multiversx-sc] +version = "=0.53.2" +features = ["esdt-token-payment-legacy-decode"] diff --git a/common/modules/permissions_hub_module/src/permissions_hub_module.rs b/common/modules/permissions_hub_module/src/permissions_hub_module.rs new file mode 100644 index 000000000..3b7832d06 --- /dev/null +++ b/common/modules/permissions_hub_module/src/permissions_hub_module.rs @@ -0,0 +1,32 @@ +#![no_std] + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[multiversx_sc::module] +pub trait PermissionsHubModule { + fn require_user_whitelisted(&self, user: &ManagedAddress, authorized_address: &ManagedAddress) { + let permissions_hub_address = self.permissions_hub_address().get(); + let is_whitelisted: bool = self + .permissions_hub_proxy(permissions_hub_address) + .is_whitelisted(user, authorized_address) + .execute_on_dest_context(); + + require!(is_whitelisted, "Caller is not whitelisted by the user"); + } + + #[only_owner] + #[endpoint(setPermissionsHubAddress)] + fn set_permissions_hub_address(&self, address: ManagedAddress) { + self.permissions_hub_address().set(&address); + } + + #[proxy] + fn permissions_hub_proxy( + &self, + sc_address: ManagedAddress, + ) -> permissions_hub::Proxy; + + #[storage_mapper("permissionsHubAddress")] + fn permissions_hub_address(&self) -> SingleValueMapper; +} diff --git a/dex/farm-with-locked-rewards/Cargo.toml b/dex/farm-with-locked-rewards/Cargo.toml index 9e96ef3e4..1968a43a9 100644 --- a/dex/farm-with-locked-rewards/Cargo.toml +++ b/dex/farm-with-locked-rewards/Cargo.toml @@ -41,6 +41,12 @@ path = "../../common/modules/utils" [dependencies.permissions_module] path = "../../common/modules/permissions_module" +[dependencies.permissions_hub_module] +path = "../../common/modules/permissions_hub_module" + +[dependencies.original_owner_helper] +path = "../../common/modules/original_owner_helper" + [dependencies.sc_whitelist_module] path = "../../common/modules/sc_whitelist_module" diff --git a/dex/farm-with-locked-rewards/src/external_interaction.rs b/dex/farm-with-locked-rewards/src/external_interaction.rs index d2e97f513..e435812d1 100644 --- a/dex/farm-with-locked-rewards/src/external_interaction.rs +++ b/dex/farm-with-locked-rewards/src/external_interaction.rs @@ -16,6 +16,8 @@ pub trait ExternalInteractionsModule: + farm_token::FarmTokenModule + pausable::PausableModule + permissions_module::PermissionsModule + + permissions_hub_module::PermissionsHubModule + + original_owner_helper::OriginalOwnerHelperModule + sc_whitelist_module::SCWhitelistModule + events::EventsModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule @@ -45,7 +47,13 @@ pub trait ExternalInteractionsModule: let caller = self.blockchain().get_caller(); self.require_user_whitelisted(&user, &caller); - self.check_additional_payments_original_owner(&user); + let payments = self.get_non_empty_payments(); + let farm_token_mapper = self.farm_token(); + self.check_additional_payments_original_owner::>( + &user, + &payments, + &farm_token_mapper, + ); let boosted_rewards = self.claim_only_boosted_payment(&user); let new_farm_token = self.enter_farm::>(user.clone()); @@ -71,8 +79,13 @@ pub trait ExternalInteractionsModule: #[payable("*")] #[endpoint(claimRewardsOnBehalf)] fn claim_rewards_on_behalf(&self) -> ClaimRewardsResultType { - let user = self.check_and_return_original_owner(); + let payments = self.get_non_empty_payments(); + let farm_token_mapper = self.farm_token(); let caller = self.blockchain().get_caller(); + let user = self.check_and_return_original_owner::>( + &payments, + &farm_token_mapper, + ); self.require_user_whitelisted(&user, &caller); let claim_rewards_result = self.claim_rewards::>(user.clone()); @@ -94,78 +107,4 @@ pub trait ExternalInteractionsModule: (claim_rewards_result.new_farm_token, locked_rewards_payment).into() } - - fn check_and_return_original_owner(&self) -> ManagedAddress { - let payments = self.call_value().all_esdt_transfers().clone_value(); - let farm_token_mapper = self.farm_token(); - let mut original_owner = ManagedAddress::zero(); - for payment in payments.into_iter() { - let attributes: FarmTokenAttributes = - farm_token_mapper.get_token_attributes(payment.token_nonce); - - if original_owner.is_zero() { - original_owner = attributes.original_owner; - } else { - require!( - original_owner == attributes.original_owner, - "All position must have the same original owner" - ); - } - } - - require!( - !original_owner.is_zero(), - "Original owner could not be identified" - ); - - original_owner - } - - fn check_additional_payments_original_owner(&self, user: &ManagedAddress) { - let payments = self.call_value().all_esdt_transfers().clone_value(); - if payments.len() == 1 { - return; - } - - let farm_token_mapper = self.farm_token(); - let farm_token_id = farm_token_mapper.get_token_id(); - for payment in payments.into_iter() { - if payment.token_identifier != farm_token_id { - continue; - } - - let attributes: FarmTokenAttributes = - farm_token_mapper.get_token_attributes(payment.token_nonce); - - require!( - user == &attributes.original_owner, - "Provided address is not the same as the original owner" - ); - } - } - - fn require_user_whitelisted(&self, user: &ManagedAddress, authorized_address: &ManagedAddress) { - let permissions_hub_address = self.permissions_hub_address().get(); - let is_whitelisted: bool = self - .permissions_hub_proxy(permissions_hub_address) - .is_whitelisted(user, authorized_address) - .execute_on_dest_context(); - - require!(is_whitelisted, "Caller is not whitelisted by the user"); - } - - #[only_owner] - #[endpoint(setPermissionsHubAddress)] - fn set_permissions_hub_address(&self, address: ManagedAddress) { - self.permissions_hub_address().set(&address); - } - - #[proxy] - fn permissions_hub_proxy( - &self, - sc_address: ManagedAddress, - ) -> permissions_hub::Proxy; - - #[storage_mapper("permissionsHubAddress")] - fn permissions_hub_address(&self) -> SingleValueMapper; } diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index 30877509f..98a048dfe 100644 --- a/dex/farm-with-locked-rewards/src/lib.rs +++ b/dex/farm-with-locked-rewards/src/lib.rs @@ -26,6 +26,8 @@ pub trait Farm: + utils::UtilsModule + pausable::PausableModule + permissions_module::PermissionsModule + + permissions_hub_module::PermissionsHubModule + + original_owner_helper::OriginalOwnerHelperModule + sc_whitelist_module::SCWhitelistModule + events::EventsModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule @@ -55,6 +57,7 @@ pub trait Farm: farming_token_id: TokenIdentifier, division_safety_constant: BigUint, owner: ManagedAddress, + timestamp_oracle_address: ManagedAddress, admins: MultiValueEncoded, ) { self.base_farm_init( @@ -65,6 +68,8 @@ pub trait Farm: admins, ); + self.set_timestamp_oracle_address(timestamp_oracle_address); + let current_epoch = self.blockchain().get_block_epoch(); self.first_week_start_epoch().set(current_epoch); diff --git a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs index 990b5bddd..826d9ae78 100644 --- a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs +++ b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs @@ -17,16 +17,14 @@ use fees_collector_mock::*; use energy_factory::{energy::EnergyModule, SimpleLockEnergy}; use energy_query::{Energy, EnergyQueryModule}; -use farm_boosted_yields::{ - boosted_yields_factors::BoostedYieldsFactorsModule, - custom_reward_logic::CustomRewardLogicModule, -}; +use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactorsModule; use farm_token::FarmTokenModule; use farm_with_locked_rewards::{external_interaction::ExternalInteractionsModule, Farm}; use locking_module::lock_with_energy_module::LockWithEnergyModule; use multiversx_sc_modules::pause::PauseModule; use pausable::{PausableModule, State}; use permissions_hub::PermissionsHub; +use permissions_hub_module::PermissionsHubModule; use rewards::RewardsModule; use sc_whitelist_module::SCWhitelistModule; use simple_lock::locked_token::LockedTokenModule; @@ -197,6 +195,7 @@ where farming_token_id, division_safety_constant, managed_address!(&owner), + managed_address!(timestamp_oracle_wrapper.address_ref()), MultiValueEncoded::new(), ); @@ -220,9 +219,6 @@ where sc.set_energy_factory_address(managed_address!( energy_factory_wrapper.address_ref() )); - sc.set_timestamp_oracle_address(managed_address!( - timestamp_oracle_wrapper.address_ref() - )); sc.set_permissions_hub_address(managed_address!( permissions_hub_wrapper.address_ref() )); @@ -309,7 +305,7 @@ where &self.energy_factory_wrapper, &rust_biguint!(0), |sc| { - sc.user_energy(&managed_address!(user)).set(&Energy::new( + sc.user_energy(&managed_address!(user)).set(Energy::new( BigInt::from(managed_biguint!(energy)), last_update_epoch, managed_biguint!(locked_tokens), @@ -601,7 +597,9 @@ where &self.permissions_hub_wrapper, &rust_biguint!(0), |sc| { - sc.whitelist(managed_address!(address_to_whitelist)); + let mut addresses = MultiValueEncoded::new(); + addresses.push(managed_address!(address_to_whitelist)); + sc.whitelist(addresses); }, ) .assert_ok(); diff --git a/dex/farm-with-locked-rewards/wasm/Cargo.lock b/dex/farm-with-locked-rewards/wasm/Cargo.lock index 4461437a9..87136c504 100644 --- a/dex/farm-with-locked-rewards/wasm/Cargo.lock +++ b/dex/farm-with-locked-rewards/wasm/Cargo.lock @@ -129,9 +129,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -178,8 +180,10 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -393,6 +397,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -424,6 +436,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" diff --git a/dex/farm-with-locked-rewards/wasm/src/lib.rs b/dex/farm-with-locked-rewards/wasm/src/lib.rs index a2c843da9..5635a0d71 100644 --- a/dex/farm-with-locked-rewards/wasm/src/lib.rs +++ b/dex/farm-with-locked-rewards/wasm/src/lib.rs @@ -56,12 +56,12 @@ multiversx_sc_wasm_adapter::endpoints! { removeAdmin => remove_admin_endpoint updateOwnerOrAdmin => update_owner_or_admin_endpoint getPermissions => permissions + setPermissionsHubAddress => set_permissions_hub_address addSCAddressToWhitelist => add_sc_address_to_whitelist removeSCAddressFromWhitelist => remove_sc_address_from_whitelist isSCAddressWhitelisted => is_sc_address_whitelisted enterFarmOnBehalf => enter_farm_on_behalf claimRewardsOnBehalf => claim_rewards_on_behalf - setPermissionsHubAddress => set_permissions_hub_address setBoostedYieldsFactors => set_boosted_yields_factors getBoostedYieldsFactors => get_boosted_yields_factors setTimestampOracleAddress => set_timestamp_oracle_address diff --git a/dex/farm/Cargo.toml b/dex/farm/Cargo.toml index 6429824be..f2e0e3202 100644 --- a/dex/farm/Cargo.toml +++ b/dex/farm/Cargo.toml @@ -38,6 +38,12 @@ path = "../../common/modules/pausable" [dependencies.permissions_module] path = "../../common/modules/permissions_module" +[dependencies.permissions_hub_module] +path = "../../common/modules/permissions_hub_module" + +[dependencies.original_owner_helper] +path = "../../common/modules/original_owner_helper" + [dependencies.sc_whitelist_module] path = "../../common/modules/sc_whitelist_module" diff --git a/dex/farm/src/external_interaction.rs b/dex/farm/src/external_interaction.rs index f1778cb3e..99f602c36 100644 --- a/dex/farm/src/external_interaction.rs +++ b/dex/farm/src/external_interaction.rs @@ -15,6 +15,8 @@ pub trait ExternalInteractionsModule: + farm_token::FarmTokenModule + pausable::PausableModule + permissions_module::PermissionsModule + + permissions_hub_module::PermissionsHubModule + + original_owner_helper::OriginalOwnerHelperModule + sc_whitelist_module::SCWhitelistModule + events::EventsModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule @@ -43,7 +45,13 @@ pub trait ExternalInteractionsModule: let caller = self.blockchain().get_caller(); self.require_user_whitelisted(&user, &caller); - self.check_additional_payments_original_owner(&user); + let payments = self.get_non_empty_payments(); + let farm_token_mapper = self.farm_token(); + self.check_additional_payments_original_owner::>( + &user, + &payments, + &farm_token_mapper, + ); let boosted_rewards = self.claim_only_boosted_payment(&user); @@ -62,8 +70,14 @@ pub trait ExternalInteractionsModule: #[payable("*")] #[endpoint(claimRewardsOnBehalf)] fn claim_rewards_on_behalf(&self) -> ClaimRewardsResultType { - let user = self.check_and_return_original_owner(); + let payments = self.get_non_empty_payments(); + let farm_token_mapper = self.farm_token(); + let caller = self.blockchain().get_caller(); + let user = self.check_and_return_original_owner::>( + &payments, + &farm_token_mapper, + ); self.require_user_whitelisted(&user, &caller); let claim_rewards_result = self.claim_rewards::>(user.clone()); @@ -73,78 +87,4 @@ pub trait ExternalInteractionsModule: claim_rewards_result.into() } - - fn check_and_return_original_owner(&self) -> ManagedAddress { - let payments = self.call_value().all_esdt_transfers().clone_value(); - let farm_token_mapper = self.farm_token(); - let mut original_owner = ManagedAddress::zero(); - for payment in payments.into_iter() { - let attributes: FarmTokenAttributes = - farm_token_mapper.get_token_attributes(payment.token_nonce); - - if original_owner.is_zero() { - original_owner = attributes.original_owner; - } else { - require!( - original_owner == attributes.original_owner, - "All position must have the same original owner" - ); - } - } - - require!( - !original_owner.is_zero(), - "Original owner could not be identified" - ); - - original_owner - } - - fn check_additional_payments_original_owner(&self, user: &ManagedAddress) { - let payments = self.call_value().all_esdt_transfers().clone_value(); - if payments.len() == 1 { - return; - } - - let farm_token_mapper = self.farm_token(); - let farm_token_id = farm_token_mapper.get_token_id(); - for payment in payments.into_iter() { - if payment.token_identifier != farm_token_id { - continue; - } - - let attributes: FarmTokenAttributes = - farm_token_mapper.get_token_attributes(payment.token_nonce); - - require!( - user == &attributes.original_owner, - "Provided address is not the same as the original owner" - ); - } - } - - fn require_user_whitelisted(&self, user: &ManagedAddress, authorized_address: &ManagedAddress) { - let permissions_hub_address = self.permissions_hub_address().get(); - let is_whitelisted: bool = self - .permissions_hub_proxy(permissions_hub_address) - .is_whitelisted(user, authorized_address) - .execute_on_dest_context(); - - require!(is_whitelisted, "Caller is not whitelisted by the user"); - } - - #[only_owner] - #[endpoint(setPermissionsHubAddress)] - fn set_permissions_hub_address(&self, address: ManagedAddress) { - self.permissions_hub_address().set(&address); - } - - #[proxy] - fn permissions_hub_proxy( - &self, - sc_address: ManagedAddress, - ) -> permissions_hub::Proxy; - - #[storage_mapper("permissionsHubAddress")] - fn permissions_hub_address(&self) -> SingleValueMapper; } diff --git a/dex/farm/src/lib.rs b/dex/farm/src/lib.rs index 4a211d10e..93f06c8cc 100644 --- a/dex/farm/src/lib.rs +++ b/dex/farm/src/lib.rs @@ -26,6 +26,8 @@ pub trait Farm: + farm_token::FarmTokenModule + pausable::PausableModule + permissions_module::PermissionsModule + + permissions_hub_module::PermissionsHubModule + + original_owner_helper::OriginalOwnerHelperModule + sc_whitelist_module::SCWhitelistModule + events::EventsModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule @@ -56,6 +58,7 @@ pub trait Farm: farming_token_id: TokenIdentifier, division_safety_constant: BigUint, owner: ManagedAddress, + timestamp_oracle_address: ManagedAddress, admins: MultiValueEncoded, ) { self.base_farm_init( @@ -66,6 +69,8 @@ pub trait Farm: admins, ); + self.set_timestamp_oracle_address(timestamp_oracle_address); + let current_epoch = self.blockchain().get_block_epoch(); self.first_week_start_epoch().set(current_epoch); } diff --git a/dex/farm/tests/farm_setup/farm_rewards_distr_setup.rs b/dex/farm/tests/farm_setup/farm_rewards_distr_setup.rs index 38ed867fd..a6603a78d 100644 --- a/dex/farm/tests/farm_setup/farm_rewards_distr_setup.rs +++ b/dex/farm/tests/farm_setup/farm_rewards_distr_setup.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] -use farm_boosted_yields::custom_reward_logic::CustomRewardLogicModule; use multiversx_sc::codec::multi_types::OptionalValue; use multiversx_sc::storage::mappers::StorageTokenWrapper; use multiversx_sc::types::{Address, BigUint, EsdtLocalRole, ManagedAddress, MultiValueEncoded}; @@ -114,6 +113,7 @@ where farming_token_id, division_safety_constant, ManagedAddress::::zero(), + managed_address!(timestamp_oracle_wrapper.address_ref()), MultiValueEncoded::new(), ); @@ -121,13 +121,10 @@ where sc.farm_token().set_token_id(farm_token_id); sc.per_block_reward_amount() - .set(&to_managed_biguint(per_block_reward_amount)); + .set(to_managed_biguint(per_block_reward_amount)); sc.state().set(State::Active); sc.produce_rewards_enabled().set(true); - sc.set_timestamp_oracle_address(managed_address!( - timestamp_oracle_wrapper.address_ref() - )); }) .assert_ok(); diff --git a/dex/farm/tests/farm_setup/multi_user_farm_setup.rs b/dex/farm/tests/farm_setup/multi_user_farm_setup.rs index fdec4ef02..bb790058b 100644 --- a/dex/farm/tests/farm_setup/multi_user_farm_setup.rs +++ b/dex/farm/tests/farm_setup/multi_user_farm_setup.rs @@ -24,6 +24,7 @@ use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactorsModule; use farm_token::FarmTokenModule; use pausable::{PausableModule, State}; use permissions_hub::PermissionsHub; +use permissions_hub_module::PermissionsHubModule; use sc_whitelist_module::SCWhitelistModule; use timestamp_oracle::epoch_to_timestamp::EpochToTimestampModule; use timestamp_oracle::TimestampOracle; @@ -179,6 +180,7 @@ where farming_token_id, division_safety_constant, managed_address!(&owner), + managed_address!(timestamp_oracle_wrapper.address_ref()), MultiValueEncoded::new(), ); @@ -193,9 +195,6 @@ where sc.set_energy_factory_address(managed_address!( energy_factory_wrapper.address_ref() )); - sc.set_timestamp_oracle_address(managed_address!( - timestamp_oracle_wrapper.address_ref() - )); sc.set_permissions_hub_address(managed_address!( permissions_hub_wrapper.address_ref() @@ -272,7 +271,7 @@ where &self.energy_factory_wrapper, &rust_biguint!(0), |sc| { - sc.user_energy(&managed_address!(user)).set(&Energy::new( + sc.user_energy(&managed_address!(user)).set(Energy::new( BigInt::from(managed_biguint!(energy)), last_update_epoch, managed_biguint!(locked_tokens), @@ -690,7 +689,9 @@ where &self.permissions_hub_wrapper, &rust_biguint!(0), |sc| { - sc.whitelist(managed_address!(address_to_whitelist)); + let mut addresses = MultiValueEncoded::new(); + addresses.push(managed_address!(address_to_whitelist)); + sc.whitelist(addresses); }, ) .assert_ok(); @@ -699,7 +700,7 @@ where pub fn remove_whitelist_address_on_behalf( &mut self, user: &Address, - address_to_whitelist: &Address, + address_to_remove: &Address, ) { self.b_mock .execute_tx( @@ -707,7 +708,9 @@ where &self.permissions_hub_wrapper, &rust_biguint!(0), |sc| { - sc.remove_whitelist(managed_address!(address_to_whitelist)); + let mut addresses = MultiValueEncoded::new(); + addresses.push(managed_address!(address_to_remove)); + sc.remove_whitelist(addresses); }, ) .assert_ok(); diff --git a/dex/farm/tests/farm_setup/single_user_farm_setup.rs b/dex/farm/tests/farm_setup/single_user_farm_setup.rs index 87eb38ca4..a5b1c0f54 100644 --- a/dex/farm/tests/farm_setup/single_user_farm_setup.rs +++ b/dex/farm/tests/farm_setup/single_user_farm_setup.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] use common_structs::FarmTokenAttributes; -use farm_boosted_yields::custom_reward_logic::CustomRewardLogicModule; use multiversx_sc::codec::multi_types::{MultiValue3, OptionalValue}; use multiversx_sc::storage::mappers::StorageTokenWrapper; use multiversx_sc::types::{Address, EsdtLocalRole, ManagedAddress, MultiValueEncoded}; @@ -141,6 +140,7 @@ where farming_token_id, division_safety_constant, ManagedAddress::::zero(), + managed_address!(timestamp_oracle_wrapper.address_ref()), MultiValueEncoded::new(), ); @@ -152,9 +152,6 @@ where sc.state().set(State::Active); sc.produce_rewards_enabled().set(true); - sc.set_timestamp_oracle_address(managed_address!( - timestamp_oracle_wrapper.address_ref() - )); }) .assert_ok(); diff --git a/dex/farm/tests/farm_single_user_test.rs b/dex/farm/tests/farm_single_user_test.rs index c2bede496..5f2586dcb 100644 --- a/dex/farm/tests/farm_single_user_test.rs +++ b/dex/farm/tests/farm_single_user_test.rs @@ -126,10 +126,8 @@ where let second_reward_share = DIVISION_SAFETY_CONSTANT * 10 * PER_BLOCK_REWARD_AMOUNT / current_farm_supply; let expected_reward_per_share = (first_reward_share * farm_in_amount - + second_reward_share * second_farm_in_amount - + total_amount - - 1) - / total_amount; + + second_reward_share * second_farm_in_amount) + .div_ceil(total_amount); farm_setup.enter_farm( second_farm_in_amount, @@ -174,10 +172,8 @@ fn test_exit_farm_after_enter_twice() { let second_reward_share = DIVISION_SAFETY_CONSTANT * 10 * PER_BLOCK_REWARD_AMOUNT / current_farm_supply; let prev_reward_per_share = (first_reward_share * farm_in_amount - + second_reward_share * second_farm_in_amount - + total_farm_token - - 1) - / total_farm_token; + + second_reward_share * second_farm_in_amount) + .div_ceil(total_farm_token); let new_reward_per_share = prev_reward_per_share + 25 * PER_BLOCK_REWARD_AMOUNT * DIVISION_SAFETY_CONSTANT / total_farm_token; let reward_per_share_diff = new_reward_per_share - prev_reward_per_share; diff --git a/dex/farm/wasm/Cargo.lock b/dex/farm/wasm/Cargo.lock index a40853d06..cceb61c15 100644 --- a/dex/farm/wasm/Cargo.lock +++ b/dex/farm/wasm/Cargo.lock @@ -129,9 +129,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -362,6 +364,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -393,6 +403,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" diff --git a/dex/farm/wasm/src/lib.rs b/dex/farm/wasm/src/lib.rs index b300f6917..2ae1d5525 100644 --- a/dex/farm/wasm/src/lib.rs +++ b/dex/farm/wasm/src/lib.rs @@ -53,12 +53,12 @@ multiversx_sc_wasm_adapter::endpoints! { removeAdmin => remove_admin_endpoint updateOwnerOrAdmin => update_owner_or_admin_endpoint getPermissions => permissions + setPermissionsHubAddress => set_permissions_hub_address addSCAddressToWhitelist => add_sc_address_to_whitelist removeSCAddressFromWhitelist => remove_sc_address_from_whitelist isSCAddressWhitelisted => is_sc_address_whitelisted enterFarmOnBehalf => enter_farm_on_behalf claimRewardsOnBehalf => claim_rewards_on_behalf - setPermissionsHubAddress => set_permissions_hub_address setBoostedYieldsFactors => set_boosted_yields_factors getBoostedYieldsFactors => get_boosted_yields_factors setTimestampOracleAddress => set_timestamp_oracle_address diff --git a/dex/fuzz/Cargo.toml b/dex/fuzz/Cargo.toml index 7278d4708..ff72ad77c 100644 --- a/dex/fuzz/Cargo.toml +++ b/dex/fuzz/Cargo.toml @@ -53,3 +53,6 @@ path = "../pair" [dependencies.router] path = "../router" + +[dependencies.timestamp-oracle] +path = "../../energy-integration/timestamp-oracle" diff --git a/dex/fuzz/src/fuzz_data.rs b/dex/fuzz/src/fuzz_data.rs index 8bc2be8f3..93e6e7bff 100644 --- a/dex/fuzz/src/fuzz_data.rs +++ b/dex/fuzz/src/fuzz_data.rs @@ -5,6 +5,7 @@ pub mod fuzz_data_tests { multiversx_sc::derive_imports!(); use ::config::ConfigModule; + use common_structs::Timestamp; use farm::*; use farm_token::FarmTokenModule; use multiversx_sc::codec::Empty; @@ -24,6 +25,8 @@ pub mod fuzz_data_tests { use rand::SeedableRng; use std::cell::Cell; use std::collections::HashMap; + use timestamp_oracle::epoch_to_timestamp::EpochToTimestampModule; + use timestamp_oracle::TimestampOracle; type RustBigUint = num_bigint::BigUint; @@ -66,6 +69,8 @@ pub mod fuzz_data_tests { pub const FIXED_PENALTY_PHASE_DURATION_BLOCKS: u64 = 25; pub const UNLOCK_EPOCH: u64 = 20; + pub const TIMESTAMP_PER_EPOCH: Timestamp = 24 * 60 * 60; + #[derive(Clone, TopEncode)] pub struct FuzzDexExecutorInitArgs { pub num_users: u64, @@ -394,6 +399,22 @@ pub mod fuzz_data_tests { FARM_WASM_PATH, ); + let timestamp_oracle_wrapper = blockchain_wrapper.create_sc_account( + &rust_zero, + Some(owner_addr), + timestamp_oracle::contract_obj, + "timestamp oracle", + ); + blockchain_wrapper + .execute_tx(owner_addr, ×tamp_oracle_wrapper, &rust_zero, |sc| { + sc.init(0); + + for i in 0..=21 { + sc.set_start_timestamp_for_epoch(i, i * TIMESTAMP_PER_EPOCH + 1); + } + }) + .assert_ok(); + blockchain_wrapper .execute_tx(owner_addr, &farm_wrapper, &rust_zero, |sc| { let reward_token_id = managed_token_id!(reward_token); @@ -405,6 +426,7 @@ pub mod fuzz_data_tests { farming_token_id, division_safety_constant, ManagedAddress::::zero(), + managed_address!(timestamp_oracle_wrapper.address_ref()), MultiValueEncoded::new(), ); @@ -412,7 +434,7 @@ pub mod fuzz_data_tests { sc.farm_token().set_token_id(farm_token_id); sc.per_block_reward_amount() - .set(&to_managed_biguint(per_block_reward_amount)); + .set(to_managed_biguint(per_block_reward_amount)); sc.state().set(State::Active); sc.produce_rewards_enabled().set(true); diff --git a/dex/fuzz/src/fuzz_farm.rs b/dex/fuzz/src/fuzz_farm.rs index 1660bc994..96a6a01cf 100644 --- a/dex/fuzz/src/fuzz_farm.rs +++ b/dex/fuzz/src/fuzz_farm.rs @@ -61,7 +61,7 @@ pub mod fuzz_farm_test { //randomly add all existing farm positions for merge let merge_farm_positions: bool = fuzzer_data.rng.gen(); - if merge_farm_positions && farm_setup.farmer_info.get(&caller.address).is_some() { + if merge_farm_positions && farm_setup.farmer_info.contains_key(&caller.address) { for farm_token_nonce in farm_setup.farmer_info.get(&caller.address).unwrap().iter() { let farm_token_amount = fuzzer_data.blockchain_wrapper.get_esdt_balance( &caller.address, @@ -221,7 +221,7 @@ pub mod fuzz_farm_test { // When claiming rewards, the caller uses all his farming positions let mut farm_token_amount_check = rust_biguint!(0u64); let mut payments = Vec::new(); - if farm_setup.farmer_info.get(&caller.address).is_some() { + if farm_setup.farmer_info.contains_key(&caller.address) { for farm_token_nonce in farm_setup.farmer_info.get(&caller.address).unwrap().iter() { let farm_token_amount = fuzzer_data.blockchain_wrapper.get_esdt_balance( &caller.address, @@ -320,7 +320,7 @@ pub mod fuzz_farm_test { // When compounding rewards, the caller uses all his farming positions let mut farm_token_amount_check = rust_biguint!(0u64); let mut payments = Vec::new(); - if farm_setup.farmer_info.get(&caller.address).is_some() { + if farm_setup.farmer_info.contains_key(&caller.address) { for farm_token_nonce in farm_setup.farmer_info.get(&caller.address).unwrap().iter() { let farm_token_amount = fuzzer_data.blockchain_wrapper.get_esdt_balance( &caller.address, diff --git a/dex/fuzz/src/fuzz_price_discovery.rs b/dex/fuzz/src/fuzz_price_discovery.rs index d327f947b..63f0fcc3b 100644 --- a/dex/fuzz/src/fuzz_price_discovery.rs +++ b/dex/fuzz/src/fuzz_price_discovery.rs @@ -289,7 +289,7 @@ pub mod fuzz_price_discovery_test { if redeem_token_before < redeem_token_amount_in { if redeem_token_amount_in > rust_zero { - redeem_token_amount_in = redeem_token_before.clone(); + redeem_token_amount_in.clone_from(&redeem_token_before); } else { println!("Price discovery redeem error: Not enough tokens"); fuzzer_data.statistics.price_discovery_redeem_misses += 1; diff --git a/dex/governance/tests/gov_tests.rs b/dex/governance/tests/gov_tests.rs index 1a05e7180..7a377e307 100644 --- a/dex/governance/tests/gov_tests.rs +++ b/dex/governance/tests/gov_tests.rs @@ -178,7 +178,7 @@ fn test_propose_bad_token() { }); }, ) - .assert_user_error(&String::from_utf8(UNREGISTERED_TOKEN_ID.to_vec()).unwrap()); + .assert_user_error(core::str::from_utf8(UNREGISTERED_TOKEN_ID).unwrap()); } #[test] @@ -200,7 +200,7 @@ fn test_propose_bad_amount() { }); }, ) - .assert_user_error(&String::from_utf8(NOT_ENOUGH_FUNDS_TO_PROPOSE.to_vec()).unwrap()); + .assert_user_error(core::str::from_utf8(NOT_ENOUGH_FUNDS_TO_PROPOSE).unwrap()); } #[test] @@ -418,7 +418,7 @@ fn test_basic_reclaim() { sc.redeem(); }, ) - .assert_user_error(&String::from_utf8(VOTING_PERIOD_NOT_ENDED.to_vec()).unwrap()); + .assert_user_error(core::str::from_utf8(VOTING_PERIOD_NOT_ENDED).unwrap()); gov_setup .blockchain_wrapper @@ -495,7 +495,7 @@ fn test_vote() { sc.upvote(0); }, ) - .assert_user_error(&String::from_utf8(PROPOSAL_NOT_ACTIVE.to_vec()).unwrap()); + .assert_user_error(core::str::from_utf8(PROPOSAL_NOT_ACTIVE).unwrap()); gov_setup .blockchain_wrapper @@ -565,7 +565,7 @@ fn test_vote() { sc.redeem(); }, ) - .assert_user_error(&String::from_utf8(VOTING_PERIOD_NOT_ENDED.to_vec()).unwrap()); + .assert_user_error(core::str::from_utf8(VOTING_PERIOD_NOT_ENDED).unwrap()); gov_setup .blockchain_wrapper diff --git a/dex/pair/src/contexts/base.rs b/dex/pair/src/contexts/base.rs index 751ca7fc1..94ff5c292 100644 --- a/dex/pair/src/contexts/base.rs +++ b/dex/pair/src/contexts/base.rs @@ -97,7 +97,7 @@ where } } -impl<'a, C> Drop for StorageCache<'a, C> +impl Drop for StorageCache<'_, C> where C: crate::config::ConfigModule, { diff --git a/dex/pair/tests/pair_rs_test.rs b/dex/pair/tests/pair_rs_test.rs index 723b3ddf0..8752ee2f4 100644 --- a/dex/pair/tests/pair_rs_test.rs +++ b/dex/pair/tests/pair_rs_test.rs @@ -1387,7 +1387,7 @@ fn add_liquidity_through_simple_lock_proxy() { pair_setup.b_mock.set_block_epoch(5); // add liquidity through simple-lock SC - one locked (WEGLD) token, one unlocked (MEX) - let transfers = vec![ + let transfers = [ TxTokenTransfer { token_identifier: LOCKED_TOKEN_ID.to_vec(), nonce: 1, diff --git a/dex/permissions-hub/src/lib.rs b/dex/permissions-hub/src/lib.rs index 9887fe90c..7dfe4392d 100644 --- a/dex/permissions-hub/src/lib.rs +++ b/dex/permissions-hub/src/lib.rs @@ -11,18 +11,28 @@ pub trait PermissionsHub { #[upgrade] fn upgrade(&self) {} - #[endpoint(whitelist)] - fn whitelist(&self, address_to_whitelist: ManagedAddress) { + #[endpoint] + fn whitelist(&self, addresses_to_whitelist: MultiValueEncoded) { let caller = self.blockchain().get_caller(); - self.user_whitelisted_addresses(&caller) - .insert(address_to_whitelist); + for address_to_whitelist in addresses_to_whitelist.into_iter() { + require!( + self.user_whitelisted_addresses(&caller) + .insert(address_to_whitelist), + "Address is already whitelisted" + ); + } } #[endpoint(removeWhitelist)] - fn remove_whitelist(&self, address_to_remove: ManagedAddress) { + fn remove_whitelist(&self, addresses_to_remove: MultiValueEncoded) { let caller = self.blockchain().get_caller(); - self.user_whitelisted_addresses(&caller) - .swap_remove(&address_to_remove); + for address_to_remove in addresses_to_remove.into_iter() { + require!( + self.user_whitelisted_addresses(&caller) + .swap_remove(&address_to_remove), + "Address is not whitelisted" + ); + } } #[only_owner] diff --git a/dex/proxy-deployer/Cargo.toml b/dex/proxy-deployer/Cargo.toml index d703dda15..5043ec5a9 100644 --- a/dex/proxy-deployer/Cargo.toml +++ b/dex/proxy-deployer/Cargo.toml @@ -8,24 +8,33 @@ publish = false [lib] path = "src/lib.rs" -[dependencies.farm] -path = "../farm" +[dependencies.multiversx-sc] +version = "=0.53.2" +features = ["esdt-token-payment-legacy-decode"] -[dependencies.pausable] -path = "../../common/modules/pausable" +[dependencies.farm-staking] +path = "../../farm-staking/farm-staking" -[dependencies.config] -path = "../../common/modules/farm/config" +[dependencies.common_structs] +path = "../../common/common_structs" -[dependencies.farm_token] -path = "../../common/modules/farm/farm_token" +[dependencies.permissions_module] +path = "../../common/modules/permissions_module" -[dependencies.multiversx-sc] -version = "=0.53.2" -features = ["esdt-token-payment-legacy-decode"] +[dependencies.pausable] +path = "../../common/modules/pausable" + +[dependencies.farm-boosted-yields] +path = "../../energy-integration/farm-boosted-yields" [dev-dependencies] num-bigint = "0.4.2" [dev-dependencies.multiversx-sc-scenario] version = "=0.53.2" + +[dev-dependencies.farm_token] +path = "../../common/modules/farm/farm_token" + +[dev-dependencies.timestamp-oracle] +path = "../../energy-integration/timestamp-oracle" diff --git a/dex/proxy-deployer/elrond.json b/dex/proxy-deployer/elrond.json deleted file mode 100644 index 736553962..000000000 --- a/dex/proxy-deployer/elrond.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "language": "rust" -} \ No newline at end of file diff --git a/dex/proxy-deployer/src/deploy.rs b/dex/proxy-deployer/src/deploy.rs new file mode 100644 index 000000000..9e03ee986 --- /dev/null +++ b/dex/proxy-deployer/src/deploy.rs @@ -0,0 +1,107 @@ +use common_structs::Epoch; + +use crate::storage::DeployerType; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +const DIVISION_SAFETY_CONST: u64 = 1_000_000_000_000_000_000; + +#[multiversx_sc::module] +pub trait DeployModule: crate::storage::StorageModule { + #[endpoint(deployFarmStakingContract)] + fn deploy_farm_staking_contract( + &self, + farming_token_id: TokenIdentifier, + max_apr: BigUint, + min_unbond_epochs: Epoch, + ) -> ManagedAddress { + self.require_correct_deployer_type(DeployerType::FarmStaking); + require!( + !self.all_used_tokens().contains(&farming_token_id), + "Token already used" + ); + + let caller = self.get_caller_not_blacklisted(); + let deployed_sc_address = self.deploy_farm_staking_from_source( + caller.clone(), + farming_token_id.clone(), + max_apr, + min_unbond_epochs, + ); + self.add_new_contract(&caller, &deployed_sc_address, farming_token_id); + + deployed_sc_address + } + + fn get_caller_not_blacklisted(&self) -> ManagedAddress { + let caller = self.blockchain().get_caller(); + let caller_id = self.address_id().get_id_or_insert(&caller); + require!( + !self.user_blacklist().contains(&caller_id), + "user blacklisted" + ); + + caller + } + + fn deploy_farm_staking_from_source( + &self, + caller: ManagedAddress, + farming_token_id: TokenIdentifier, + max_apr: BigUint, + min_unbond_epochs: Epoch, + ) -> ManagedAddress { + let owner = self.blockchain().get_owner_address(); + + let own_sc_address = self.blockchain().get_sc_address(); + let mut admins = MultiValueEncoded::new(); + admins.push(caller); + admins.push(own_sc_address); + + let template = self.template_address().get(); + let code_metadata = + CodeMetadata::PAYABLE_BY_SC | CodeMetadata::READABLE | CodeMetadata::UPGRADEABLE; + let timestamp_oracle_address = self.timestamp_oracle_address().get(); + + let (deployed_sc_address, ()) = self + .farm_staking_deploy_proxy() + .init( + farming_token_id, + DIVISION_SAFETY_CONST, + max_apr, + min_unbond_epochs, + owner, + timestamp_oracle_address, + admins, + ) + .deploy_from_source(&template, code_metadata); + + deployed_sc_address + } + + fn add_new_contract( + &self, + caller: &ManagedAddress, + deployed_sc_address: &ManagedAddress, + farming_token_id: TokenIdentifier, + ) { + let contract_id = self.address_id().insert_new(deployed_sc_address); + let _ = self.all_deployed_contracts().insert(contract_id); + self.address_for_token(&farming_token_id).set(contract_id); + self.token_for_address(contract_id).set(&farming_token_id); + let _ = self.all_used_tokens().insert(farming_token_id); + + let caller_id = self.address_id().get_id_non_zero(caller); + let _ = self.contracts_by_address(caller_id).insert(contract_id); + self.contract_owner(contract_id).set(caller_id); + } + + fn require_correct_deployer_type(&self, requested_type: DeployerType) { + let deployer_type = self.deployer_type().get(); + require!(deployer_type == requested_type, "Invalid deployer type"); + } + + #[proxy] + fn farm_staking_deploy_proxy(&self) -> farm_staking::Proxy; +} diff --git a/dex/proxy-deployer/src/farm_deploy.rs b/dex/proxy-deployer/src/farm_deploy.rs deleted file mode 100644 index eb1c88e53..000000000 --- a/dex/proxy-deployer/src/farm_deploy.rs +++ /dev/null @@ -1,87 +0,0 @@ -multiversx_sc::imports!(); - -use farm::ProxyTrait as _; - -const DIVISION_SAFETY_CONST: u64 = 1_000_000_000_000_000_000; - -#[multiversx_sc::module] -pub trait FarmDeployModule { - #[endpoint(deployFarm)] - fn deploy_farm( - &self, - reward_token_id: TokenIdentifier, - farming_token_id: TokenIdentifier, - ) -> ManagedAddress { - let owner = self.blockchain().get_owner_address(); - let caller = self.blockchain().get_caller(); - let mut admins_list = MultiValueEncoded::new(); - admins_list.push(caller.clone()); - - let farm_template = self.farm_template_address().get(); - let code_metadata = - CodeMetadata::PAYABLE_BY_SC | CodeMetadata::READABLE | CodeMetadata::UPGRADEABLE; - let (new_farm_address, ()) = self - .farm_deploy_proxy() - .init( - reward_token_id, - farming_token_id, - DIVISION_SAFETY_CONST, - owner, - admins_list, - ) - .deploy_from_source(&farm_template, code_metadata); - - self.deployer_farm_addresses(&caller) - .update(|farm_addresses| { - farm_addresses.push(new_farm_address.clone()); - }); - self.deployers_list().insert(caller); - - new_farm_address - } - - #[only_owner] - #[endpoint(callFarmEndpoint)] - fn call_farm_endpoint( - &self, - farm_address: ManagedAddress, - function_name: ManagedBuffer, - args: MultiValueEncoded, - ) { - let gas_left = self.blockchain().get_gas_left(); - let mut contract_call = self - .send() - .contract_call::<()>(farm_address, function_name) - .with_gas_limit(gas_left); - - for arg in args { - contract_call.push_raw_argument(arg); - } - let _: IgnoreValue = contract_call.execute_on_dest_context(); - } - - #[view(getAllDeployedFarms)] - fn get_all_deployed_farms(&self) -> ManagedVec { - let mut all_farm_addresses = ManagedVec::new(); - for deployer in self.deployers_list().iter() { - all_farm_addresses.append_vec(self.deployer_farm_addresses(&deployer).get()); - } - all_farm_addresses - } - - #[proxy] - fn farm_deploy_proxy(&self) -> farm::Proxy; - - #[storage_mapper("farmTemplateAddress")] - fn farm_template_address(&self) -> SingleValueMapper; - - #[storage_mapper("deployersList")] - fn deployers_list(&self) -> UnorderedSetMapper; - - #[view(getDeployerFarmAddresses)] - #[storage_mapper("deployerFarmAddresses")] - fn deployer_farm_addresses( - &self, - deployer_address: &ManagedAddress, - ) -> SingleValueMapper>; -} diff --git a/dex/proxy-deployer/src/lib.rs b/dex/proxy-deployer/src/lib.rs index 7f7f0c16a..fa82e8bee 100644 --- a/dex/proxy-deployer/src/lib.rs +++ b/dex/proxy-deployer/src/lib.rs @@ -1,19 +1,48 @@ #![no_std] +use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactors; +use storage::DeployerType; + multiversx_sc::imports!(); -pub mod farm_deploy; +pub mod deploy; +pub mod remove_contracts; +pub mod set_contract_active; +pub mod storage; +pub mod views; #[multiversx_sc::contract] -pub trait ProxyDeployer: farm_deploy::FarmDeployModule { +pub trait ProxyDeployer: + deploy::DeployModule + + set_contract_active::SetContractActiveModule + + remove_contracts::RemoveContractsModule + + storage::StorageModule + + views::ViewModule +{ #[init] - fn init(&self, farm_template_address: ManagedAddress) { + fn init( + &self, + template_address: ManagedAddress, + deployer_type: DeployerType, + timestamp_oracle_address: ManagedAddress, + boosted_yields_factors: BoostedYieldsFactors, + ) { require!( - self.blockchain().is_smart_contract(&farm_template_address), + self.blockchain().is_smart_contract(&template_address), "Invalid farm template address" ); + require!(deployer_type != DeployerType::None, "Invalid deployer type"); + require!( + self.blockchain() + .is_smart_contract(×tamp_oracle_address), + "Invalid timestamp oracle address" + ); - self.farm_template_address().set(&farm_template_address); + self.template_address().set(template_address); + self.deployer_type().set(deployer_type); + self.timestamp_oracle_address() + .set(timestamp_oracle_address); + self.boosted_yields_factors().set(boosted_yields_factors); } #[upgrade] diff --git a/dex/proxy-deployer/src/remove_contracts.rs b/dex/proxy-deployer/src/remove_contracts.rs new file mode 100644 index 000000000..76d4ba989 --- /dev/null +++ b/dex/proxy-deployer/src/remove_contracts.rs @@ -0,0 +1,104 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use permissions_module::ProxyTrait as _; + +#[derive(TypeAbi, TopEncode)] +pub struct RemoveResult { + pub any_farms_left: bool, +} + +#[multiversx_sc::module] +pub trait RemoveContractsModule: crate::storage::StorageModule { + #[only_owner] + #[endpoint(blacklistUser)] + fn blacklist_user(&self, user: ManagedAddress) { + let user_id = self.address_id().get_id_or_insert(&user); + self.user_blacklist().add(&user_id); + } + + #[only_owner] + #[endpoint(removeAllByDeployer)] + fn remove_all_by_deployer( + &self, + deployer_address: ManagedAddress, + max_to_remove: usize, + ) -> RemoveResult { + let id_mapper = self.address_id(); + let deployer_id = id_mapper.get_id_non_zero(&deployer_address); + let mut contracts_mapper = self.contracts_by_address(deployer_id); + + let total_contracts = contracts_mapper.len(); + let to_remove = core::cmp::min(total_contracts, max_to_remove); + for _ in 0..to_remove { + let contract_id = contracts_mapper.get_by_index(1); + let contract_address = self.get_by_id(&id_mapper, contract_id); + let _ = contracts_mapper.swap_remove(&contract_id); + + self.remove_admin(contract_address, deployer_address.clone()); + self.remove_contract(contract_id); + } + + RemoveResult { + any_farms_left: total_contracts > max_to_remove, + } + } + + #[only_owner] + #[endpoint(removeSingleContract)] + fn remove_single_contract(&self, contract: ManagedAddress) { + let id_mapper = self.address_id(); + let contract_id = id_mapper.get_id_non_zero(&contract); + let deployer_id = self.contract_owner(contract_id).get(); + require!(deployer_id != 0, "Contract already removed"); + + let _ = self + .contracts_by_address(deployer_id) + .swap_remove(&contract_id); + + let deployer_address = self.get_by_id(&id_mapper, deployer_id); + self.remove_admin(contract, deployer_address); + self.remove_contract(contract_id); + } + + #[endpoint(removeOwnContract)] + fn remove_own_contract(&self, contract: ManagedAddress) { + let caller = self.blockchain().get_caller(); + let id_mapper = self.address_id(); + let caller_id = id_mapper.get_id_non_zero(&caller); + let contract_id = id_mapper.get_id_non_zero(&contract); + let deployer_id = self.contract_owner(contract_id).get(); + require!( + caller_id == deployer_id, + "Only the contract deployer may call this endpoint" + ); + + let _ = self + .contracts_by_address(deployer_id) + .swap_remove(&contract_id); + + let deployer_address = self.get_by_id(&id_mapper, deployer_id); + self.remove_admin(contract, deployer_address); + self.remove_contract(contract_id); + } + + fn remove_admin(&self, contract: ManagedAddress, user: ManagedAddress) { + self.remove_user_proxy(contract) + .remove_admin_endpoint(user) + .execute_on_dest_context() + } + + fn remove_contract(&self, contract_id: AddressId) { + let _ = self.all_deployed_contracts().swap_remove(&contract_id); + let token_for_address = self.token_for_address(contract_id).take(); + let _ = self.all_used_tokens().swap_remove(&token_for_address); + self.address_for_token(&token_for_address).clear(); + self.contract_owner(contract_id).clear(); + } + + // For now, both farm and farm_staking use the same internal permissions module. + // + // Create two separate proxies if this if this ever changes. + #[proxy] + fn remove_user_proxy(&self, sc_address: ManagedAddress) -> farm_staking::Proxy; +} diff --git a/dex/proxy-deployer/src/set_contract_active.rs b/dex/proxy-deployer/src/set_contract_active.rs new file mode 100644 index 000000000..43095107b --- /dev/null +++ b/dex/proxy-deployer/src/set_contract_active.rs @@ -0,0 +1,86 @@ +use common_structs::Percent; +use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactors; +use farm_boosted_yields::boosted_yields_factors::ProxyTrait as _; +use farm_staking::custom_rewards::ProxyTrait as _; +use pausable::ProxyTrait as _; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait SetContractActiveModule: crate::storage::StorageModule { + /// Boosted yields percent must be >= 0 (0%) and <= 10_000 (100%) + /// + /// Only callable by contract deployer + /// + /// Calling this endpoint multiple times is the same as calling the specific endpoints in farm by the deployer + /// + /// NOTE: Must issue farm token first! + #[endpoint(setContractActive)] + fn set_contract_active( + &self, + contract: ManagedAddress, + rewards_per_block: BigUint, + boosted_yields_percent: Percent, + ) { + let id_mapper = self.address_id(); + let contract_id = id_mapper.get_id_non_zero(&contract); + + let caller = self.blockchain().get_caller(); + let caller_id = id_mapper.get_id_non_zero(&caller); + let owner_id = self.contract_owner(contract_id).get(); + require!( + caller_id == owner_id, + "Only contract owner may call this endpoint" + ); + + let boosted_yields_factors = self.boosted_yields_factors().get(); + self.set_rewards_per_block(contract.clone(), rewards_per_block); + self.set_boosted_yields_factors(contract.clone(), boosted_yields_factors); + self.set_boosted_yields_percent(contract.clone(), boosted_yields_percent); + self.unpause_contract(contract); + } + + fn set_rewards_per_block(&self, contract: ManagedAddress, rewards_per_block: BigUint) { + self.set_contract_active_proxy(contract) + .set_per_block_rewards(rewards_per_block) + .execute_on_dest_context() + } + + fn set_boosted_yields_factors( + &self, + contract: ManagedAddress, + factors: BoostedYieldsFactors, + ) { + self.set_contract_active_proxy(contract) + .set_boosted_yields_factors( + factors.max_rewards_factor, + factors.user_rewards_energy_const, + factors.user_rewards_farm_const, + factors.min_energy_amount, + factors.min_farm_amount, + ) + .execute_on_dest_context() + } + + fn set_boosted_yields_percent( + &self, + contract: ManagedAddress, + boosted_yields_percent: Percent, + ) { + self.set_contract_active_proxy(contract) + .set_boosted_yields_rewards_percentage(boosted_yields_percent) + .execute_on_dest_context() + } + + fn unpause_contract(&self, contract: ManagedAddress) { + self.set_contract_active_proxy(contract) + .resume() + .execute_on_dest_context() + } + + #[proxy] + fn set_contract_active_proxy( + &self, + sc_address: ManagedAddress, + ) -> farm_staking::Proxy; +} diff --git a/dex/proxy-deployer/src/storage.rs b/dex/proxy-deployer/src/storage.rs new file mode 100644 index 000000000..35beba626 --- /dev/null +++ b/dex/proxy-deployer/src/storage.rs @@ -0,0 +1,61 @@ +use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactors; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(TypeAbi, TopEncode, TopDecode, Clone, Copy, PartialEq)] +pub enum DeployerType { + None, + FarmStaking, + FarmWithTopUp, +} + +#[multiversx_sc::module] +pub trait StorageModule { + fn get_by_id(&self, id_mapper: &AddressToIdMapper, id: AddressId) -> ManagedAddress { + let opt_address = id_mapper.get_address(id); + require!(opt_address.is_some(), "Invalid setup"); + + unsafe { opt_address.unwrap_unchecked() } + } + + #[view(getDeployerType)] + #[storage_mapper("deployerType")] + fn deployer_type(&self) -> SingleValueMapper; + + #[view(getTemplateAddress)] + #[storage_mapper("templateAddress")] + fn template_address(&self) -> SingleValueMapper; + + #[storage_mapper("addressId")] + fn address_id(&self) -> AddressToIdMapper; + + #[storage_mapper("contractOwner")] + fn contract_owner(&self, contract_id: AddressId) -> SingleValueMapper; + + #[storage_mapper("contractByAddress")] + fn contracts_by_address(&self, address_id: AddressId) -> UnorderedSetMapper; + + #[storage_mapper("addrForTok")] + fn address_for_token(&self, token_id: &TokenIdentifier) -> SingleValueMapper; + + #[storage_mapper("tokForAddr")] + fn token_for_address(&self, address_id: AddressId) -> SingleValueMapper; + + #[storage_mapper("allUsedTokens")] + fn all_used_tokens(&self) -> UnorderedSetMapper; + + #[storage_mapper("allDeployedContracts")] + fn all_deployed_contracts(&self) -> UnorderedSetMapper; + + #[storage_mapper("userBlacklist")] + fn user_blacklist(&self) -> WhitelistMapper; + + #[view(getTimestampOracleAddress)] + #[storage_mapper("timestampOracleAddress")] + fn timestamp_oracle_address(&self) -> SingleValueMapper; + + #[view(getBoostedYieldsFactors)] + #[storage_mapper("boostedYieldsFactors")] + fn boosted_yields_factors(&self) -> SingleValueMapper>; +} diff --git a/dex/proxy-deployer/src/views.rs b/dex/proxy-deployer/src/views.rs new file mode 100644 index 000000000..6135e0c50 --- /dev/null +++ b/dex/proxy-deployer/src/views.rs @@ -0,0 +1,147 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[multiversx_sc::module] +pub trait ViewModule: crate::storage::StorageModule { + #[view(isUserBlacklisted)] + fn is_user_blacklisted(&self, user: ManagedAddress) -> bool { + let user_id = self.address_id().get_id(&user); + if user_id == NULL_ID { + return false; + } + + self.user_blacklist().contains(&user_id) + } + + #[view(getAddressForToken)] + fn get_address_for_token(&self, token_id: TokenIdentifier) -> OptionalValue { + let mapper = self.address_for_token(&token_id); + if mapper.is_empty() { + return OptionalValue::None; + } + + let id = mapper.get(); + let addr = self.get_by_id(&self.address_id(), id); + + OptionalValue::Some(addr) + } + + #[view(getTokenForAddress)] + fn get_token_for_address( + &self, + contract_address: ManagedAddress, + ) -> OptionalValue { + let contract_id = self.address_id().get_id(&contract_address); + if contract_id == NULL_ID { + return OptionalValue::None; + } + + let mapper = self.token_for_address(contract_id); + if mapper.is_empty() { + return OptionalValue::None; + } + + let token_id = mapper.get(); + + OptionalValue::Some(token_id) + } + + #[view(getContractOwner)] + fn get_contract_owner( + &self, + contract_address: ManagedAddress, + ) -> OptionalValue { + let contract_id = self.address_id().get_id(&contract_address); + if contract_id == NULL_ID { + return OptionalValue::None; + } + + let owner_id = self.contract_owner(contract_id).get(); + let opt_address = self.address_id().get_address(owner_id); + match opt_address { + Some(addr) => OptionalValue::Some(addr), + None => OptionalValue::None, + } + } + + /// Indexes start at 1 + #[view(getAllUsedTokens)] + fn get_all_used_tokens( + &self, + start_index: usize, + max_entries: usize, + ) -> MultiValueEncoded { + let mapper = self.all_used_tokens(); + self.get_entries(&mapper, start_index, max_entries) + } + + /// Indexes start at 1 + #[view(getAllDeployedContractsBySc)] + fn get_all_deployed_contracts_by_sc( + &self, + start_index: usize, + max_entries: usize, + ) -> MultiValueEncoded { + let id_mapper = self.address_id(); + let mapper = self.all_deployed_contracts(); + let contract_ids = self.get_entries(&mapper, start_index, max_entries); + + let mut result = MultiValueEncoded::new(); + for contract_id in contract_ids { + let address = self.get_by_id(&id_mapper, contract_id); + result.push(address); + } + + result + } + + #[view(getAllDeployedContractsByUser)] + fn get_all_deployed_contracts_by_user( + &self, + user: ManagedAddress, + start_index: usize, + max_entries: usize, + ) -> MultiValueEncoded { + let id_mapper = self.address_id(); + let user_id = id_mapper.get_id(&user); + if user_id == NULL_ID { + return MultiValueEncoded::new(); + } + + let mapper = self.contracts_by_address(user_id); + let contract_ids = self.get_entries(&mapper, start_index, max_entries); + + let mut result = MultiValueEncoded::new(); + for contract_id in contract_ids { + let address = self.get_by_id(&id_mapper, contract_id); + result.push(address); + } + + result + } + + fn get_entries( + &self, + mapper: &UnorderedSetMapper, + start_index: usize, + max_entries: usize, + ) -> MultiValueEncoded { + require!(start_index > 0, "Invalid start index"); + + let mut items = MultiValueEncoded::new(); + let mut current_index = start_index; + let mapper_len = mapper.len(); + for _ in 0..max_entries { + if current_index > mapper_len { + break; + } + + let current_item = mapper.get_by_index(current_index); + items.push(current_item); + + current_index += 1; + } + + items + } +} diff --git a/dex/proxy-deployer/tests/proxy_deployer_farm_staking_setup/mod.rs b/dex/proxy-deployer/tests/proxy_deployer_farm_staking_setup/mod.rs new file mode 100644 index 000000000..7b155c6be --- /dev/null +++ b/dex/proxy-deployer/tests/proxy_deployer_farm_staking_setup/mod.rs @@ -0,0 +1,128 @@ +use common_structs::{Epoch, Timestamp}; +use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactors; +use multiversx_sc::types::Address; +use multiversx_sc_scenario::{ + imports::{BlockchainStateWrapper, ContractObjWrapper}, + managed_address, managed_biguint, managed_token_id, rust_biguint, DebugApi, +}; +use proxy_deployer::{ + deploy::DeployModule, set_contract_active::SetContractActiveModule, storage::DeployerType, + ProxyDeployer, +}; +use timestamp_oracle::{epoch_to_timestamp::EpochToTimestampModule, TimestampOracle}; + +pub const TIMESTAMP_PER_EPOCH: Timestamp = 24 * 60 * 60; + +pub struct ProxyDeployerFarmStakingSetup +where + ProxyDeployerBuilder: 'static + Copy + Fn() -> proxy_deployer::ContractObj, + FarmStakingBuilder: 'static + Copy + Fn() -> farm_staking::ContractObj, +{ + pub b_mock: BlockchainStateWrapper, + pub owner: Address, + pub user: Address, + pub proxy_deployer_wrapper: + ContractObjWrapper, ProxyDeployerBuilder>, + pub template_wrapper: + ContractObjWrapper, FarmStakingBuilder>, +} + +impl + ProxyDeployerFarmStakingSetup +where + ProxyDeployerBuilder: 'static + Copy + Fn() -> proxy_deployer::ContractObj, + FarmStakingBuilder: 'static + Copy + Fn() -> farm_staking::ContractObj, +{ + pub fn new( + proxy_builder: ProxyDeployerBuilder, + farm_staking_builder: FarmStakingBuilder, + ) -> Self { + let rust_zero = rust_biguint!(0); + let mut b_mock = BlockchainStateWrapper::new(); + let owner = b_mock.create_user_account(&rust_zero); + let user = b_mock.create_user_account(&rust_zero); + let proxy_deployer_wrapper = + b_mock.create_sc_account(&rust_zero, Some(&owner), proxy_builder, "proxy deployer"); + let template_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(&owner), + farm_staking_builder, + "farm staking template", + ); + + let timestamp_oracle_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(&owner), + timestamp_oracle::contract_obj, + "timestamp oracle", + ); + b_mock + .execute_tx(&owner, ×tamp_oracle_wrapper, &rust_zero, |sc| { + sc.init(0); + + for i in 0..=21 { + sc.set_start_timestamp_for_epoch(i, i * TIMESTAMP_PER_EPOCH + 1); + } + }) + .assert_ok(); + + b_mock + .execute_tx(&owner, &proxy_deployer_wrapper, &rust_zero, |sc| { + sc.init( + managed_address!(template_wrapper.address_ref()), + DeployerType::FarmStaking, + managed_address!(timestamp_oracle_wrapper.address_ref()), + BoostedYieldsFactors { + max_rewards_factor: managed_biguint!(10), + user_rewards_energy_const: managed_biguint!(3), + user_rewards_farm_const: managed_biguint!(2), + min_energy_amount: managed_biguint!(1), + min_farm_amount: managed_biguint!(1), + }, + ); + }) + .assert_ok(); + + Self { + b_mock, + owner, + user, + proxy_deployer_wrapper, + template_wrapper, + } + } + + pub fn deploy_farm_staking(&mut self, token_id: &[u8], max_apr: u64, min_unbond_epochs: Epoch) { + self.b_mock + .execute_tx( + &self.user, + &self.proxy_deployer_wrapper, + &rust_biguint!(0), + |sc| { + sc.deploy_farm_staking_contract( + managed_token_id!(token_id), + managed_biguint!(max_apr), + min_unbond_epochs, + ); + }, + ) + .assert_ok(); + } + + pub fn set_contract_active(&mut self, contract: &Address) { + self.b_mock + .execute_tx( + &self.user, + &self.proxy_deployer_wrapper, + &rust_biguint!(0), + |sc| { + sc.set_contract_active( + managed_address!(contract), + managed_biguint!(1_000), + 1_000, // 10% + ); + }, + ) + .assert_ok(); + } +} diff --git a/dex/proxy-deployer/tests/proxy_deployer_farm_staking_tests.rs b/dex/proxy-deployer/tests/proxy_deployer_farm_staking_tests.rs new file mode 100644 index 000000000..ad9db9c74 --- /dev/null +++ b/dex/proxy-deployer/tests/proxy_deployer_farm_staking_tests.rs @@ -0,0 +1,262 @@ +use farm_staking::{custom_rewards::CustomRewardsModule, stake_farm::StakeFarmModule}; +use farm_token::FarmTokenModule; +use multiversx_sc::{ + codec::Empty, + imports::{OptionalValue, StorageTokenWrapper}, + types::EsdtLocalRole, +}; +use multiversx_sc_scenario::{managed_address, managed_biguint, managed_token_id, rust_biguint}; +use proxy_deployer::{remove_contracts::RemoveContractsModule, views::ViewModule}; +use proxy_deployer_farm_staking_setup::ProxyDeployerFarmStakingSetup; + +pub mod proxy_deployer_farm_staking_setup; + +#[test] +fn setup_test() { + let _ = ProxyDeployerFarmStakingSetup::new( + proxy_deployer::contract_obj, + farm_staking::contract_obj, + ); +} + +#[test] +fn deploy_farm_staking_test() { + let mut setup = ProxyDeployerFarmStakingSetup::new( + proxy_deployer::contract_obj, + farm_staking::contract_obj, + ); + + let new_sc_wrapper = setup.b_mock.prepare_deploy_from_sc( + setup.proxy_deployer_wrapper.address_ref(), + farm_staking::contract_obj, + ); + setup.deploy_farm_staking(&b"COOLTOK-123456"[..], 7_500, 10); + + // user call admin function on new farm staking + setup + .b_mock + .execute_tx(&setup.user, &new_sc_wrapper, &rust_biguint!(0), |sc| { + sc.farm_token() + .set_token_id(managed_token_id!(b"MYCOOLFARM-123456")); + + sc.set_per_block_rewards(managed_biguint!(1_000)); + }) + .assert_ok(); + + // owner remove the contracts + let user_addr = setup.user.clone(); + setup + .b_mock + .execute_tx( + &setup.owner, + &setup.proxy_deployer_wrapper, + &rust_biguint!(0), + |sc| { + sc.remove_all_by_deployer(managed_address!(&user_addr), 1); + }, + ) + .assert_ok(); + + // user try call admin function after removed + setup + .b_mock + .execute_tx(&setup.user, &new_sc_wrapper, &rust_biguint!(0), |sc| { + sc.set_per_block_rewards(managed_biguint!(1_000)); + }) + .assert_user_error("Permission denied"); +} + +#[test] +fn remove_single_contract_test() { + let mut setup = ProxyDeployerFarmStakingSetup::new( + proxy_deployer::contract_obj, + farm_staking::contract_obj, + ); + + let new_sc_wrapper = setup.b_mock.prepare_deploy_from_sc( + setup.proxy_deployer_wrapper.address_ref(), + farm_staking::contract_obj, + ); + setup.deploy_farm_staking(&b"COOLTOK-123456"[..], 7_500, 10); + + // owner remove the contract + setup + .b_mock + .execute_tx( + &setup.owner, + &setup.proxy_deployer_wrapper, + &rust_biguint!(0), + |sc| { + sc.remove_single_contract(managed_address!(new_sc_wrapper.address_ref())); + }, + ) + .assert_ok(); +} + +#[test] +fn user_remove_contract_test() { + let mut setup = ProxyDeployerFarmStakingSetup::new( + proxy_deployer::contract_obj, + farm_staking::contract_obj, + ); + + let new_sc_wrapper = setup.b_mock.prepare_deploy_from_sc( + setup.proxy_deployer_wrapper.address_ref(), + farm_staking::contract_obj, + ); + + setup.deploy_farm_staking(&b"COOLTOK-123456"[..], 7_500, 10); + + // user remove the contract + setup + .b_mock + .execute_tx( + &setup.user, + &setup.proxy_deployer_wrapper, + &rust_biguint!(0), + |sc| { + sc.remove_own_contract(managed_address!(new_sc_wrapper.address_ref())); + }, + ) + .assert_ok(); +} + +#[test] +fn set_contract_active_test() { + let mut setup = ProxyDeployerFarmStakingSetup::new( + proxy_deployer::contract_obj, + farm_staking::contract_obj, + ); + + let new_sc_wrapper = setup.b_mock.prepare_deploy_from_sc( + setup.proxy_deployer_wrapper.address_ref(), + farm_staking::contract_obj, + ); + let farming_token_id = b"COOLTOK-123456"; + let farm_token_id = b"MYCOOLFARM-123456"; + setup.deploy_farm_staking(&farming_token_id[..], 7_500, 10); + + // simulate farm token issue + setup + .b_mock + .execute_tx(&setup.user, &new_sc_wrapper, &rust_biguint!(0), |sc| { + sc.farm_token() + .set_token_id(managed_token_id!(farm_token_id)); + }) + .assert_ok(); + + setup.b_mock.set_esdt_local_roles( + new_sc_wrapper.address_ref(), + farm_token_id, + &[EsdtLocalRole::NftCreate, EsdtLocalRole::NftBurn], + ); + + // set user balance + setup + .b_mock + .set_esdt_balance(&setup.user, &farming_token_id[..], &rust_biguint!(1_000)); + + // user try enter farm before it's ready + setup + .b_mock + .execute_esdt_transfer( + &setup.user, + &new_sc_wrapper, + &farming_token_id[..], + 0, + &rust_biguint!(1_000), + |sc| { + sc.stake_farm_endpoint(OptionalValue::None); + }, + ) + .assert_user_error("Not active"); + + setup.set_contract_active(new_sc_wrapper.address_ref()); + + // user enter farm again + setup + .b_mock + .execute_esdt_transfer( + &setup.user, + &new_sc_wrapper, + &farming_token_id[..], + 0, + &rust_biguint!(1_000), + |sc| { + sc.stake_farm_endpoint(OptionalValue::None); + }, + ) + .assert_ok(); + + setup.b_mock.check_nft_balance( + &setup.user, + &farm_token_id[..], + 1, + &rust_biguint!(1_000), + Option::<&Empty>::None, + ); +} + +#[test] +fn views_test() { + let mut setup = ProxyDeployerFarmStakingSetup::new( + proxy_deployer::contract_obj, + farm_staking::contract_obj, + ); + + let new_sc_wrapper = setup.b_mock.prepare_deploy_from_sc( + setup.proxy_deployer_wrapper.address_ref(), + farm_staking::contract_obj, + ); + let farming_token_id = b"COOLTOK-123456"; + setup.deploy_farm_staking(&farming_token_id[..], 7_500, 10); + + let user_addr = setup.user.clone(); + setup + .b_mock + .execute_query(&setup.proxy_deployer_wrapper, |sc| { + let is_blacklisted = sc.is_user_blacklisted(managed_address!(&user_addr)); + assert!(!is_blacklisted); + + let addr_for_tok = sc + .get_address_for_token(managed_token_id!(farming_token_id)) + .into_option() + .unwrap(); + assert_eq!(addr_for_tok, managed_address!(new_sc_wrapper.address_ref())); + + let token_for_addr = sc + .get_token_for_address(managed_address!(new_sc_wrapper.address_ref())) + .into_option() + .unwrap(); + assert_eq!(token_for_addr, managed_token_id!(farming_token_id)); + + let contract_owner = sc + .get_contract_owner(managed_address!(new_sc_wrapper.address_ref())) + .into_option() + .unwrap(); + assert_eq!(contract_owner, managed_address!(&user_addr)); + + let all_used_tokens = sc.get_all_used_tokens(1, 1_000); + assert_eq!(all_used_tokens.len(), 1); + assert_eq!( + (*all_used_tokens.to_vec().get(0)).clone(), + managed_token_id!(farming_token_id) + ); + + let all_deployed_contracts = sc.get_all_deployed_contracts_by_sc(1, 1_000); + assert_eq!(all_deployed_contracts.len(), 1); + assert_eq!( + (*all_deployed_contracts.to_vec().get(0)).clone(), + managed_address!(new_sc_wrapper.address_ref()) + ); + + let all_deployed_by_user = + sc.get_all_deployed_contracts_by_user(managed_address!(&user_addr), 1, 1_000); + assert_eq!(all_deployed_by_user.len(), 1); + assert_eq!( + (*all_deployed_by_user.to_vec().get(0)).clone(), + managed_address!(new_sc_wrapper.address_ref()) + ); + }) + .assert_ok(); +} diff --git a/dex/proxy-deployer/wasm/Cargo.lock b/dex/proxy-deployer/wasm/Cargo.lock index d012a5597..ba8ce0e7c 100644 --- a/dex/proxy-deployer/wasm/Cargo.lock +++ b/dex/proxy-deployer/wasm/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "arrayvec" @@ -129,9 +129,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -158,6 +160,40 @@ dependencies = [ "weekly-rewards-splitting", ] +[[package]] +name = "farm-staking" +version = "0.0.0" +dependencies = [ + "common_errors", + "common_structs", + "config", + "contexts", + "energy-factory", + "energy-query", + "events", + "farm", + "farm-boosted-yields", + "farm_base_impl", + "farm_token", + "fixed-supply-token", + "math", + "mergeable", + "multiversx-sc", + "multiversx-sc-modules", + "original_owner_helper", + "pair", + "pausable", + "permissions-hub", + "permissions_hub_module", + "permissions_module", + "rewards", + "sc_whitelist_module", + "token_send", + "utils", + "week-timekeeping", + "weekly-rewards-splitting", +] + [[package]] name = "farm_base_impl" version = "0.0.0" @@ -354,6 +390,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -385,6 +429,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" @@ -407,11 +459,12 @@ dependencies = [ name = "proxy-deployer" version = "0.0.0" dependencies = [ - "config", - "farm", - "farm_token", + "common_structs", + "farm-boosted-yields", + "farm-staking", "multiversx-sc", "pausable", + "permissions_module", ] [[package]] diff --git a/dex/proxy-deployer/wasm/src/lib.rs b/dex/proxy-deployer/wasm/src/lib.rs index 620fcb058..de33813fe 100644 --- a/dex/proxy-deployer/wasm/src/lib.rs +++ b/dex/proxy-deployer/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 4 +// Endpoints: 17 // Async Callback (empty): 1 -// Total number of exported functions: 7 +// Total number of exported functions: 20 #![no_std] @@ -20,10 +20,23 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - deployFarm => deploy_farm - callFarmEndpoint => call_farm_endpoint - getAllDeployedFarms => get_all_deployed_farms - getDeployerFarmAddresses => deployer_farm_addresses + deployFarmStakingContract => deploy_farm_staking_contract + setContractActive => set_contract_active + blacklistUser => blacklist_user + removeAllByDeployer => remove_all_by_deployer + removeSingleContract => remove_single_contract + removeOwnContract => remove_own_contract + getDeployerType => deployer_type + getTemplateAddress => template_address + getTimestampOracleAddress => timestamp_oracle_address + getBoostedYieldsFactors => boosted_yields_factors + isUserBlacklisted => is_user_blacklisted + getAddressForToken => get_address_for_token + getTokenForAddress => get_token_for_address + getContractOwner => get_contract_owner + getAllUsedTokens => get_all_used_tokens + getAllDeployedContractsBySc => get_all_deployed_contracts_by_sc + getAllDeployedContractsByUser => get_all_deployed_contracts_by_user ) } diff --git a/dex/router/src/contract.rs b/dex/router/src/contract.rs index f879e36e6..800a20b91 100644 --- a/dex/router/src/contract.rs +++ b/dex/router/src/contract.rs @@ -39,7 +39,7 @@ pub trait Router: self.pair_creation_enabled().set_if_empty(false); self.init_factory(pair_template_address_opt.into_option()); - self.owner().set(&self.blockchain().get_caller()); + self.owner().set(self.blockchain().get_caller()); } #[upgrade] diff --git a/energy-integration/common-modules/weekly-rewards-splitting/src/lib.rs b/energy-integration/common-modules/weekly-rewards-splitting/src/lib.rs index 52c71d4dc..5b6686739 100644 --- a/energy-integration/common-modules/weekly-rewards-splitting/src/lib.rs +++ b/energy-integration/common-modules/weekly-rewards-splitting/src/lib.rs @@ -184,60 +184,3 @@ pub trait WeeklyRewardsSplittingModule: } } } - -#[cfg(test)] -mod tests { - use multiversx_sc_scenario::{managed_biguint, DebugApi}; - - use super::*; - - #[derive(TypeAbi, TopEncode, Clone, PartialEq, Debug)] - pub struct OldClaimProgress { - pub energy: Energy, - pub week: Week, - } - - #[test] - fn decode_old_claim_progress_to_new_test() { - DebugApi::dummy(); - - let old_progress = OldClaimProgress { - energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), - week: 2, - }; - let mut old_progress_encoded = ManagedBuffer::::new(); - let _ = old_progress.top_encode(&mut old_progress_encoded); - - let new_progress_decoded = ClaimProgress::top_decode(old_progress_encoded).unwrap(); - assert_eq!( - new_progress_decoded, - ClaimProgress { - energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), - week: 2, - enter_timestamp: 0, - } - ); - } - - #[test] - fn encoded_decode_new_progress_test() { - DebugApi::dummy(); - - let new_progress = ClaimProgress { - energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), - week: 2, - enter_timestamp: 0, - }; - let mut new_progress_encoded = ManagedBuffer::::new(); - let _ = new_progress.top_encode(&mut new_progress_encoded); - let new_progress_decoded = ClaimProgress::top_decode(new_progress_encoded).unwrap(); - assert_eq!( - new_progress_decoded, - ClaimProgress { - energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), - week: 2, - enter_timestamp: 0, - } - ); - } -} diff --git a/energy-integration/common-modules/weekly-rewards-splitting/tests/encode_decode_test.rs b/energy-integration/common-modules/weekly-rewards-splitting/tests/encode_decode_test.rs new file mode 100644 index 000000000..0d917c71c --- /dev/null +++ b/energy-integration/common-modules/weekly-rewards-splitting/tests/encode_decode_test.rs @@ -0,0 +1,57 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use common_structs::Week; +use energy_query::Energy; +use multiversx_sc_scenario::{managed_biguint, DebugApi}; +use weekly_rewards_splitting::ClaimProgress; + +#[derive(TypeAbi, TopEncode, Clone, PartialEq, Debug)] +pub struct OldClaimProgress { + pub energy: Energy, + pub week: Week, +} + +#[test] +fn decode_old_claim_progress_to_new_test() { + DebugApi::dummy(); + + let old_progress = OldClaimProgress { + energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), + week: 2, + }; + let mut old_progress_encoded = ManagedBuffer::::new(); + let _ = old_progress.top_encode(&mut old_progress_encoded); + + let new_progress_decoded = ClaimProgress::top_decode(old_progress_encoded).unwrap(); + assert_eq!( + new_progress_decoded, + ClaimProgress { + energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), + week: 2, + enter_timestamp: 0, + } + ); +} + +#[test] +fn encoded_decode_new_progress_test() { + DebugApi::dummy(); + + let new_progress = ClaimProgress { + energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), + week: 2, + enter_timestamp: 0, + }; + let mut new_progress_encoded = ManagedBuffer::::new(); + let _ = new_progress.top_encode(&mut new_progress_encoded); + let new_progress_decoded = ClaimProgress::top_decode(new_progress_encoded).unwrap(); + assert_eq!( + new_progress_decoded, + ClaimProgress { + energy: Energy::new(BigInt::::zero(), 10, managed_biguint!(20)), + week: 2, + enter_timestamp: 0, + } + ); +} diff --git a/energy-integration/energy-factory-mock/src/lib.rs b/energy-integration/energy-factory-mock/src/lib.rs index d3354e67e..9ed54cc6c 100644 --- a/energy-integration/energy-factory-mock/src/lib.rs +++ b/energy-integration/energy-factory-mock/src/lib.rs @@ -17,7 +17,7 @@ pub trait EnergyFactoryMock { total_locked_tokens: BigUint, ) { let current_epoch = self.blockchain().get_block_epoch(); - self.user_energy(&user).set(&Energy::new( + self.user_energy(&user).set(Energy::new( BigInt::from(energy_amount), current_epoch, total_locked_tokens, diff --git a/energy-integration/energy-update/wasm/Cargo.lock b/energy-integration/energy-update/wasm/Cargo.lock index 5879e51a0..414f83b21 100644 --- a/energy-integration/energy-update/wasm/Cargo.lock +++ b/energy-integration/energy-update/wasm/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "arrayvec" @@ -147,9 +147,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -372,6 +374,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -403,6 +413,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" diff --git a/energy-integration/farm-boosted-yields/src/boosted_yields_factors.rs b/energy-integration/farm-boosted-yields/src/boosted_yields_factors.rs index 1bd34eb6c..c355cb490 100644 --- a/energy-integration/farm-boosted-yields/src/boosted_yields_factors.rs +++ b/energy-integration/farm-boosted-yields/src/boosted_yields_factors.rs @@ -109,7 +109,7 @@ pub trait BoostedYieldsFactorsModule: min_energy_amount: BigUint, min_farm_amount: BigUint, ) { - self.require_caller_has_admin_permissions(); + self.require_caller_has_owner_permissions(); require!( min_energy_amount > 0 && min_farm_amount > 0, "Min amounts must be greater than 0" diff --git a/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs b/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs index 93e6da275..1f1a09b48 100644 --- a/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs +++ b/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs @@ -253,7 +253,7 @@ where &self.energy_factory_wrapper, &rust_biguint!(0), |sc| { - sc.user_energy(&managed_address!(user)).set(&Energy::new( + sc.user_energy(&managed_address!(user)).set(Energy::new( BigInt::from(managed_biguint!(energy_amount)), current_epoch, managed_biguint!(total_locked_tokens), diff --git a/energy-integration/governance-v2/src/configurable.rs b/energy-integration/governance-v2/src/configurable.rs index 12751ce7f..b74f83b0b 100644 --- a/energy-integration/governance-v2/src/configurable.rs +++ b/energy-integration/governance-v2/src/configurable.rs @@ -2,33 +2,32 @@ use crate::errors::ERROR_NOT_AN_ESDT; multiversx_sc::imports!(); -/// # MultiversX smart contract module - Governance -/// -/// This is a standard smart contract module, that when added to a smart contract offers governance features: -/// - proposing actions -/// - voting/downvoting a certain proposal -/// - after a voting period, either putting the action in a queue (if it reached quorum), or canceling -/// -/// Voting is done through energy. -/// -/// The module provides the following configurable parameters: -/// - `minEnergyForPropose` - the minimum energy required for submitting a proposal -/// - `quorum` - the minimum number of (`votes` minus `downvotes`) at the end of voting period -/// - `maxActionsPerProposal` - Maximum number of actions (transfers and/or smart contract calls) that a proposal may have -/// - `votingDelayInBlocks` - Number of blocks to wait after a block is proposed before being able to vote/downvote that proposal -/// - `votingPeriodInBlocks` - Number of blocks the voting period lasts (voting delay does not count towards this) -/// - `lockTimeAfterVotingEndsInBlocks` - Number of blocks to wait before a successful proposal can be executed -/// -/// The module also provides events for most actions that happen: -/// - `proposalCreated` - triggers when a proposal is created. Also provoides all the relevant information, like proposer, actions etc. -/// - `voteCast` - user voted on a proposal -/// - `downvoteCast` - user downvoted a proposal -/// - `proposalCanceled`, `proposalQueued` and `proposalExecuted` - provides the ID of the specific proposal -/// - `userDeposit` - a user deposited some tokens needed for a future payable action -/// -/// Please note that although the main contract can modify the module's storage directly, it is not recommended to do so, -/// as that defeats the whole purpose of having governance. These parameters should only be modified through actions. -/// +// # MultiversX smart contract module - Governance +// +// This is a standard smart contract module, that when added to a smart contract offers governance features: +// - proposing actions +// - voting/downvoting a certain proposal +// - after a voting period, either putting the action in a queue (if it reached quorum), or canceling +// +// Voting is done through energy. +// +// The module provides the following configurable parameters: +// - `minEnergyForPropose` - the minimum energy required for submitting a proposal +// - `quorum` - the minimum number of (`votes` minus `downvotes`) at the end of voting period +// - `maxActionsPerProposal` - Maximum number of actions (transfers and/or smart contract calls) that a proposal may have +// - `votingDelayInBlocks` - Number of blocks to wait after a block is proposed before being able to vote/downvote that proposal +// - `votingPeriodInBlocks` - Number of blocks the voting period lasts (voting delay does not count towards this) +// - `lockTimeAfterVotingEndsInBlocks` - Number of blocks to wait before a successful proposal can be executed +// +// The module also provides events for most actions that happen: +// - `proposalCreated` - triggers when a proposal is created. Also provoides all the relevant information, like proposer, actions etc. +// - `voteCast` - user voted on a proposal +// - `downvoteCast` - user downvoted a proposal +// - `proposalCanceled`, `proposalQueued` and `proposalExecuted` - provides the ID of the specific proposal +// - `userDeposit` - a user deposited some tokens needed for a future payable action +// +// Please note that although the main contract can modify the module's storage directly, it is not recommended to do so, +// as that defeats the whole purpose of having governance. These parameters should only be modified through actions. const MIN_VOTING_DELAY: u64 = 1; const MAX_VOTING_DELAY: u64 = 100_800; // 1 Week diff --git a/energy-integration/governance-v2/tests/gov_test_setup/mod.rs b/energy-integration/governance-v2/tests/gov_test_setup/mod.rs index 465222293..4809577bf 100644 --- a/energy-integration/governance-v2/tests/gov_test_setup/mod.rs +++ b/energy-integration/governance-v2/tests/gov_test_setup/mod.rs @@ -79,25 +79,25 @@ where .execute_tx(&owner, &energy_factory_wrapper, &rust_zero, |sc| { sc.init(); sc.user_energy(&managed_address!(&first_user)) - .set(&Energy::new( + .set(Energy::new( BigInt::from(managed_biguint!(USER_ENERGY)), 0, managed_biguint!(0), )); sc.user_energy(&managed_address!(&second_user)) - .set(&Energy::new( + .set(Energy::new( BigInt::from(managed_biguint!(USER_ENERGY)), 0, managed_biguint!(0), )); sc.user_energy(&managed_address!(&third_user)) - .set(&Energy::new( + .set(Energy::new( BigInt::from(managed_biguint!(USER_ENERGY + 210_000)), 0, managed_biguint!(0), )); sc.user_energy(&managed_address!(&no_energy_user)) - .set(&Energy::new( + .set(Energy::new( BigInt::from(managed_biguint!(0)), 0, managed_biguint!(0), diff --git a/farm-staking/farm-staking-proxy/Cargo.toml b/farm-staking/farm-staking-proxy/Cargo.toml index ee0e406e3..4720c7ee1 100644 --- a/farm-staking/farm-staking-proxy/Cargo.toml +++ b/farm-staking/farm-staking-proxy/Cargo.toml @@ -66,6 +66,9 @@ path = "../../energy-integration/common-modules/energy-query" [dependencies.permissions-hub] path = "../../dex/permissions-hub" +[dependencies.permissions_hub_module] +path = "../../common/modules/permissions_hub_module" + [dev-dependencies] num-bigint = "0.4.2" diff --git a/farm-staking/farm-staking-proxy/src/lib.rs b/farm-staking/farm-staking-proxy/src/lib.rs index 4840bd965..f28d5d083 100644 --- a/farm-staking/farm-staking-proxy/src/lib.rs +++ b/farm-staking/farm-staking-proxy/src/lib.rs @@ -14,6 +14,7 @@ pub trait FarmStakingProxy: + external_contracts_interactions::ExternalContractsInteractionsModule + lp_farm_token::LpFarmTokenModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule + + permissions_hub_module::PermissionsHubModule + utils::UtilsModule + token_send::TokenSendModule + energy_query::EnergyQueryModule diff --git a/farm-staking/farm-staking-proxy/src/proxy_actions/claim.rs b/farm-staking/farm-staking-proxy/src/proxy_actions/claim.rs index 057c59206..a3a40a5de 100644 --- a/farm-staking/farm-staking-proxy/src/proxy_actions/claim.rs +++ b/farm-staking/farm-staking-proxy/src/proxy_actions/claim.rs @@ -83,14 +83,12 @@ pub trait ProxyClaimModule: let lp_farm_rewards = lp_farm_claim_rewards_result.lp_farm_rewards; let staking_farm_rewards = staking_farm_claim_rewards_result.staking_farm_rewards; - let claim_result = ClaimDualYieldResult { + dual_yield_token_mapper.nft_burn(payment.token_nonce, &payment.amount); + + ClaimDualYieldResult { lp_farm_rewards, staking_farm_rewards, new_dual_yield_tokens, - }; - - dual_yield_token_mapper.nft_burn(payment.token_nonce, &payment.amount); - - claim_result + } } } diff --git a/farm-staking/farm-staking-proxy/src/proxy_actions/external_interaction.rs b/farm-staking/farm-staking-proxy/src/proxy_actions/external_interaction.rs index 12d8b257d..722bc2eb8 100644 --- a/farm-staking/farm-staking-proxy/src/proxy_actions/external_interaction.rs +++ b/farm-staking/farm-staking-proxy/src/proxy_actions/external_interaction.rs @@ -15,6 +15,7 @@ pub trait ProxyExternalInteractionsModule: + crate::proxy_actions::stake::ProxyStakeModule + crate::proxy_actions::claim::ProxyClaimModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule + + permissions_hub_module::PermissionsHubModule + utils::UtilsModule + token_send::TokenSendModule + energy_query::EnergyQueryModule @@ -115,29 +116,4 @@ pub trait ProxyExternalInteractionsModule: attributes.original_owner } - - fn require_user_whitelisted(&self, user: &ManagedAddress, authorized_address: &ManagedAddress) { - let permissions_hub_address = self.permissions_hub_address().get(); - let is_whitelisted: bool = self - .permissions_hub_proxy(permissions_hub_address) - .is_whitelisted(user, authorized_address) - .execute_on_dest_context(); - - require!(is_whitelisted, "Caller is not whitelisted by the user"); - } - - #[only_owner] - #[endpoint(setPermissionsHubAddress)] - fn set_permissions_hub_address(&self, address: ManagedAddress) { - self.permissions_hub_address().set(&address); - } - - #[proxy] - fn permissions_hub_proxy( - &self, - sc_address: ManagedAddress, - ) -> permissions_hub::Proxy; - - #[storage_mapper("permissionsHubAddress")] - fn permissions_hub_address(&self) -> SingleValueMapper; } diff --git a/farm-staking/farm-staking-proxy/src/proxy_actions/stake.rs b/farm-staking/farm-staking-proxy/src/proxy_actions/stake.rs index 26e9b2af7..9c4ee127a 100644 --- a/farm-staking/farm-staking-proxy/src/proxy_actions/stake.rs +++ b/farm-staking/farm-staking-proxy/src/proxy_actions/stake.rs @@ -95,12 +95,11 @@ pub trait ProxyStakeModule: }; let new_dual_yield_tokens = self.create_dual_yield_tokens(&dual_yield_token_mapper, &new_attributes); - let output_payments = StakeProxyResult { + + StakeProxyResult { dual_yield_tokens: new_dual_yield_tokens, staking_boosted_rewards: staking_farm_enter_result.boosted_rewards, lp_farm_boosted_rewards, - }; - - output_payments + } } } diff --git a/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_external_contracts/mod.rs b/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_external_contracts/mod.rs index 277d13e7e..1a6ca5dc9 100644 --- a/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_external_contracts/mod.rs +++ b/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_external_contracts/mod.rs @@ -1,7 +1,6 @@ use energy_factory::token_whitelist::TokenWhitelistModule; use energy_factory::SimpleLockEnergy; use energy_query::EnergyQueryModule; -use farm_boosted_yields::custom_reward_logic::CustomRewardLogicModule; use locking_module::lock_with_energy_module::LockWithEnergyModule; use multiversx_sc::codec::multi_types::{MultiValue3, OptionalValue}; use multiversx_sc::storage::mappers::StorageTokenWrapper; @@ -273,6 +272,7 @@ where farming_token_id, division_safety_constant, ManagedAddress::::zero(), + managed_address!(timestamp_oracle_address), MultiValueEncoded::new(), ); @@ -290,7 +290,6 @@ where .set(managed_address!(energy_factory_address)); sc.energy_factory_address() .set(managed_address!(energy_factory_address)); - sc.set_timestamp_oracle_address(managed_address!(timestamp_oracle_address)); }) .assert_ok(); diff --git a/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_interactions/mod.rs b/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_interactions/mod.rs index 6aef1b170..640af81b4 100644 --- a/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_interactions/mod.rs +++ b/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_interactions/mod.rs @@ -6,7 +6,7 @@ use energy_query::Energy; use farm_with_locked_rewards::Farm; use multiversx_sc::{ codec::multi_types::OptionalValue, - types::{Address, BigInt}, + types::{Address, BigInt, MultiValueEncoded}, }; use multiversx_sc_scenario::{ managed_address, managed_biguint, managed_token_id, rust_biguint, @@ -31,6 +31,7 @@ use farm_staking_proxy::proxy_actions::stake::ProxyStakeModule; use farm_staking_proxy::proxy_actions::unstake::ProxyUnstakeModule; use permissions_hub::PermissionsHub; +use permissions_hub_module::PermissionsHubModule; use sc_whitelist_module::SCWhitelistModule; use timestamp_oracle::{epoch_to_timestamp::EpochToTimestampModule, TimestampOracle}; @@ -738,7 +739,9 @@ where &self.permissions_hub_wrapper, &rust_biguint!(0), |sc| { - sc.whitelist(managed_address!(address_to_whitelist)); + let mut addresses = MultiValueEncoded::new(); + addresses.push(managed_address!(address_to_whitelist)); + sc.whitelist(addresses); }, ) .assert_ok(); @@ -757,7 +760,7 @@ where &self.energy_factory_wrapper, &rust_biguint!(0), |sc| { - sc.user_energy(&managed_address!(user)).set(&Energy::new( + sc.user_energy(&managed_address!(user)).set(Energy::new( BigInt::from(managed_biguint!(energy)), last_update_epoch, managed_biguint!(locked_tokens), diff --git a/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_setup/mod.rs b/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_setup/mod.rs index 14095b958..834cc75fb 100644 --- a/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_setup/mod.rs +++ b/farm-staking/farm-staking-proxy/tests/staking_farm_with_lp_staking_contract_setup/mod.rs @@ -1,6 +1,5 @@ use energy_query::EnergyQueryModule; use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactorsModule; -use farm_boosted_yields::custom_reward_logic::CustomRewardLogicModule; use multiversx_sc::storage::mappers::StorageTokenWrapper; use multiversx_sc::types::{Address, EsdtLocalRole, ManagedAddress, MultiValueEncoded}; use multiversx_sc_scenario::{ @@ -49,6 +48,7 @@ where max_apr, UNBOND_EPOCHS, ManagedAddress::::zero(), + managed_address!(timestamp_oracle_address), MultiValueEncoded::new(), ); @@ -64,7 +64,6 @@ where sc.last_reward_block_nonce() .set(BLOCK_NONCE_AFTER_PAIR_SETUP); sc.reward_capacity().set(&managed_biguint!(REWARD_CAPACITY)); - sc.set_timestamp_oracle_address(managed_address!(timestamp_oracle_address)); }) .assert_ok(); diff --git a/farm-staking/farm-staking-proxy/wasm/Cargo.lock b/farm-staking/farm-staking-proxy/wasm/Cargo.lock index 211fad7a4..fdebecdd2 100644 --- a/farm-staking/farm-staking-proxy/wasm/Cargo.lock +++ b/farm-staking/farm-staking-proxy/wasm/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "arrayvec" @@ -129,9 +129,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -178,9 +180,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -208,6 +212,7 @@ dependencies = [ "pair", "pausable", "permissions-hub", + "permissions_hub_module", "rewards", "sc_whitelist_module", "token_send", @@ -243,8 +248,10 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -456,6 +463,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -487,6 +502,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" diff --git a/farm-staking/farm-staking-proxy/wasm/src/lib.rs b/farm-staking/farm-staking-proxy/wasm/src/lib.rs index 3632ff09e..f37700a58 100644 --- a/farm-staking/farm-staking-proxy/wasm/src/lib.rs +++ b/farm-staking/farm-staking-proxy/wasm/src/lib.rs @@ -29,6 +29,7 @@ multiversx_sc_wasm_adapter::endpoints! { getFarmTokenId => staking_farm_token_id getLpTokenId => lp_token_id getLpFarmTokenId => lp_farm_token_id + setPermissionsHubAddress => set_permissions_hub_address setEnergyFactoryAddress => set_energy_factory_address getEnergyFactoryAddress => energy_factory_address addSCAddressToWhitelist => add_sc_address_to_whitelist @@ -39,7 +40,6 @@ multiversx_sc_wasm_adapter::endpoints! { unstakeFarmTokens => unstake_farm_tokens stakeFarmOnBehalf => stake_farm_on_behalf claimDualYieldOnBehalf => claim_dual_yield_on_behalf - setPermissionsHubAddress => set_permissions_hub_address ) } diff --git a/farm-staking/farm-staking/Cargo.toml b/farm-staking/farm-staking/Cargo.toml index 1253b39f6..11ec5acb0 100644 --- a/farm-staking/farm-staking/Cargo.toml +++ b/farm-staking/farm-staking/Cargo.toml @@ -53,6 +53,12 @@ path = "../../common/modules/pausable" [dependencies.permissions_module] path = "../../common/modules/permissions_module" +[dependencies.permissions_hub_module] +path = "../../common/modules/permissions_hub_module" + +[dependencies.original_owner_helper] +path = "../../common/modules/original_owner_helper" + [dependencies.sc_whitelist_module] path = "../../common/modules/sc_whitelist_module" diff --git a/farm-staking/farm-staking/src/external_interaction.rs b/farm-staking/farm-staking/src/external_interaction.rs index 8dfa3107b..3e99d1465 100644 --- a/farm-staking/farm-staking/src/external_interaction.rs +++ b/farm-staking/farm-staking/src/external_interaction.rs @@ -19,6 +19,8 @@ pub trait ExternalInteractionsModule: + sc_whitelist_module::SCWhitelistModule + pausable::PausableModule + permissions_module::PermissionsModule + + permissions_hub_module::PermissionsHubModule + + original_owner_helper::OriginalOwnerHelperModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule + farm_base_impl::base_farm_init::BaseFarmInitModule + farm_base_impl::base_farm_validation::BaseFarmValidationModule @@ -52,7 +54,12 @@ pub trait ExternalInteractionsModule: self.require_user_whitelisted(&user, &caller); let payments = self.get_non_empty_payments(); - self.check_additional_payments_original_owner(&user, &payments); + let farm_token_mapper = self.farm_token(); + self.check_additional_payments_original_owner::>( + &user, + &payments, + &farm_token_mapper, + ); let boosted_rewards = self.claim_only_boosted_payment(&user); let boosted_rewards_payment = @@ -82,14 +89,18 @@ pub trait ExternalInteractionsModule: #[payable("*")] #[endpoint(claimRewardsOnBehalf)] fn claim_rewards_on_behalf(&self) -> ClaimRewardsResultType { - let payment = self.call_value().single_esdt(); - let user = self.check_and_return_original_owner(&payment); + let payments = self.get_non_empty_payments(); + let farm_token_mapper = self.farm_token(); let caller = self.blockchain().get_caller(); + let user = self.check_and_return_original_owner::>( + &payments, + &farm_token_mapper, + ); self.require_user_whitelisted(&user, &caller); let claim_result = self.claim_rewards_base_no_farm_token_mint::>( user.clone(), - ManagedVec::from_single_item(payment), + payments, ); let mut virtual_farm_token = claim_result.new_farm_token.clone(); @@ -120,68 +131,4 @@ pub trait ExternalInteractionsModule: (virtual_farm_token.payment, claim_result.rewards).into() } - - fn check_and_return_original_owner(&self, payment: &EsdtTokenPayment) -> ManagedAddress { - let farm_token_mapper = self.farm_token(); - let attributes: StakingFarmTokenAttributes = - farm_token_mapper.get_token_attributes(payment.token_nonce); - - require!( - !attributes.original_owner.is_zero(), - "Original owner could not be identified" - ); - - attributes.original_owner - } - - fn check_additional_payments_original_owner( - &self, - user: &ManagedAddress, - payments: &ManagedVec, - ) { - if payments.len() == 1 { - return; - } - - let farm_token_mapper = self.farm_token(); - let farm_token_id = farm_token_mapper.get_token_id(); - for payment in payments.into_iter() { - if payment.token_identifier != farm_token_id { - continue; - } - - let attributes: StakingFarmTokenAttributes = - farm_token_mapper.get_token_attributes(payment.token_nonce); - - require!( - user == &attributes.original_owner, - "Provided address is not the same as the original owner" - ); - } - } - - fn require_user_whitelisted(&self, user: &ManagedAddress, authorized_address: &ManagedAddress) { - let permissions_hub_address = self.permissions_hub_address().get(); - let is_whitelisted: bool = self - .permissions_hub_proxy(permissions_hub_address) - .is_whitelisted(user, authorized_address) - .execute_on_dest_context(); - - require!(is_whitelisted, "Caller is not whitelisted by the user"); - } - - #[only_owner] - #[endpoint(setPermissionsHubAddress)] - fn set_permissions_hub_address(&self, address: ManagedAddress) { - self.permissions_hub_address().set(&address); - } - - #[proxy] - fn permissions_hub_proxy( - &self, - sc_address: ManagedAddress, - ) -> permissions_hub::Proxy; - - #[storage_mapper("permissionsHubAddress")] - fn permissions_hub_address(&self) -> SingleValueMapper; } diff --git a/farm-staking/farm-staking/src/lib.rs b/farm-staking/farm-staking/src/lib.rs index 16d73d80c..7399c4602 100644 --- a/farm-staking/farm-staking/src/lib.rs +++ b/farm-staking/farm-staking/src/lib.rs @@ -36,6 +36,8 @@ pub trait FarmStaking: + sc_whitelist_module::SCWhitelistModule + pausable::PausableModule + permissions_module::PermissionsModule + + permissions_hub_module::PermissionsHubModule + + original_owner_helper::OriginalOwnerHelperModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule + farm_base_impl::base_farm_init::BaseFarmInitModule + farm_base_impl::base_farm_validation::BaseFarmValidationModule @@ -71,6 +73,7 @@ pub trait FarmStaking: max_apr: BigUint, min_unbond_epochs: u64, owner: ManagedAddress, + timestamp_oracle_address: ManagedAddress, admins: MultiValueEncoded, ) { // farming and reward token are the same @@ -91,6 +94,8 @@ pub trait FarmStaking: ); self.min_unbond_epochs().set(min_unbond_epochs); + self.set_timestamp_oracle_address(timestamp_oracle_address); + let current_epoch = self.blockchain().get_block_epoch(); self.first_week_start_epoch().set(current_epoch); } diff --git a/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs b/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs index 0e16b4ae4..66235a25a 100644 --- a/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs +++ b/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs @@ -1,6 +1,5 @@ use common_structs::Timestamp; use external_interaction::ExternalInteractionsModule; -use farm_boosted_yields::custom_reward_logic::CustomRewardLogicModule; use farm_staking::claim_only_boosted_staking_rewards::ClaimOnlyBoostedStakingRewardsModule; use farm_staking::compound_stake_farm_rewards::CompoundStakeFarmRewardsModule; use multiversx_sc::codec::multi_types::OptionalValue; @@ -27,6 +26,7 @@ use farm_staking::*; use farm_token::FarmTokenModule; use pausable::{PausableModule, State}; use permissions_hub::PermissionsHub; +use permissions_hub_module::PermissionsHubModule; use rewards::RewardsModule; use timestamp_oracle::epoch_to_timestamp::EpochToTimestampModule; use timestamp_oracle::TimestampOracle; @@ -156,6 +156,7 @@ where managed_biguint!(MAX_APR), MIN_UNBOND_EPOCHS, ManagedAddress::::zero(), + managed_address!(timestamp_oracle_wrapper.address_ref()), MultiValueEncoded::new(), ); @@ -170,9 +171,6 @@ where sc.energy_factory_address() .set(managed_address!(energy_factory_wrapper.address_ref())); - sc.set_timestamp_oracle_address(managed_address!( - timestamp_oracle_wrapper.address_ref() - )); sc.set_permissions_hub_address(managed_address!( permissions_hub_wrapper.address_ref() @@ -716,7 +714,9 @@ where &self.permissions_hub_wrapper, &rust_biguint!(0), |sc| { - sc.whitelist(managed_address!(address_to_whitelist)); + let mut addresses = MultiValueEncoded::new(); + addresses.push(managed_address!(address_to_whitelist)); + sc.whitelist(addresses); }, ) .assert_ok(); @@ -785,7 +785,7 @@ where &self.energy_factory_wrapper, &rust_biguint!(0), |sc| { - sc.user_energy(&managed_address!(user)).set(&Energy::new( + sc.user_energy(&managed_address!(user)).set(Energy::new( BigInt::from(managed_biguint!(energy)), last_update_epoch, managed_biguint!(locked_tokens), diff --git a/farm-staking/farm-staking/tests/farm_staking_test.rs b/farm-staking/farm-staking/tests/farm_staking_test.rs index 4e00cfdef..4f2471fde 100644 --- a/farm-staking/farm-staking/tests/farm_staking_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_test.rs @@ -203,10 +203,8 @@ where let first_reward_share = 0; let second_reward_share = 400_000; let expected_reward_per_share = (first_reward_share * farm_in_amount - + second_reward_share * second_farm_in_amount - + total_amount - - 1) - / total_amount; + + second_reward_share * second_farm_in_amount) + .div_ceil(total_amount); farm_setup.stake_farm( &user_address, diff --git a/farm-staking/farm-staking/wasm/Cargo.lock b/farm-staking/farm-staking/wasm/Cargo.lock index fb13bc4e4..5bdef3ac7 100644 --- a/farm-staking/farm-staking/wasm/Cargo.lock +++ b/farm-staking/farm-staking/wasm/Cargo.lock @@ -129,9 +129,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -178,9 +180,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -394,6 +398,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -425,6 +437,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" diff --git a/farm-staking/farm-staking/wasm/src/lib.rs b/farm-staking/farm-staking/wasm/src/lib.rs index 0a45a0182..a8411b08a 100644 --- a/farm-staking/farm-staking/wasm/src/lib.rs +++ b/farm-staking/farm-staking/wasm/src/lib.rs @@ -59,6 +59,7 @@ multiversx_sc_wasm_adapter::endpoints! { removeAdmin => remove_admin_endpoint updateOwnerOrAdmin => update_owner_or_admin_endpoint getPermissions => permissions + setPermissionsHubAddress => set_permissions_hub_address setBurnRoleForAddress => set_burn_role_for_address stakeFarmThroughProxy => stake_farm_through_proxy stakeFarm => stake_farm_endpoint @@ -70,7 +71,6 @@ multiversx_sc_wasm_adapter::endpoints! { unbondFarm => unbond_farm stakeFarmOnBehalf => stake_farm_on_behalf claimRewardsOnBehalf => claim_rewards_on_behalf - setPermissionsHubAddress => set_permissions_hub_address claimBoostedRewards => claim_boosted_rewards setBoostedYieldsFactors => set_boosted_yields_factors getBoostedYieldsFactors => get_boosted_yields_factors diff --git a/legacy-contracts/farm-staking-proxy-v13/wasm/Cargo.lock b/legacy-contracts/farm-staking-proxy-v13/wasm/Cargo.lock index 6c0c145ee..6b1ff77aa 100644 --- a/legacy-contracts/farm-staking-proxy-v13/wasm/Cargo.lock +++ b/legacy-contracts/farm-staking-proxy-v13/wasm/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "arrayvec" @@ -129,9 +129,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -178,9 +180,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -414,6 +418,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -445,6 +457,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" diff --git a/locked-asset/proxy_dex/tests/proxy_dex_test_setup/mod.rs b/locked-asset/proxy_dex/tests/proxy_dex_test_setup/mod.rs index 64fb27a0d..a35bb84e4 100644 --- a/locked-asset/proxy_dex/tests/proxy_dex_test_setup/mod.rs +++ b/locked-asset/proxy_dex/tests/proxy_dex_test_setup/mod.rs @@ -6,10 +6,7 @@ use common_structs::{ use config::ConfigModule; use energy_factory::{locked_token_transfer::LockedTokenTransferModule, SimpleLockEnergy}; use energy_query::EnergyQueryModule; -use farm_boosted_yields::{ - boosted_yields_factors::BoostedYieldsFactorsModule, - custom_reward_logic::CustomRewardLogicModule, -}; +use farm_boosted_yields::boosted_yields_factors::BoostedYieldsFactorsModule; use farm_token::FarmTokenModule; use farm_with_locked_rewards::Farm as FarmLocked; use locking_module::lock_with_energy_module::LockWithEnergyModule; @@ -363,6 +360,7 @@ where farming_token_id, division_safety_constant, managed_address!(owner), + managed_address!(timestamp_oracle_addr), MultiValueEncoded::new(), ); @@ -386,7 +384,6 @@ where sc.set_lock_epochs(EPOCHS_IN_YEAR); sc.energy_factory_address() .set(managed_address!(simple_lock_addr)); - sc.set_timestamp_oracle_address(managed_address!(timestamp_oracle_addr)); }) .assert_ok(); diff --git a/locked-asset/proxy_dex/wasm/Cargo.lock b/locked-asset/proxy_dex/wasm/Cargo.lock index bfc773ea6..1264b51fa 100644 --- a/locked-asset/proxy_dex/wasm/Cargo.lock +++ b/locked-asset/proxy_dex/wasm/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "arrayvec" @@ -129,9 +129,11 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pair", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -178,8 +180,10 @@ dependencies = [ "mergeable", "multiversx-sc", "multiversx-sc-modules", + "original_owner_helper", "pausable", "permissions-hub", + "permissions_hub_module", "permissions_module", "rewards", "sc_whitelist_module", @@ -385,6 +389,14 @@ dependencies = [ "autocfg", ] +[[package]] +name = "original_owner_helper" +version = "0.0.0" +dependencies = [ + "common_structs", + "multiversx-sc", +] + [[package]] name = "pair" version = "0.0.0" @@ -416,6 +428,14 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "permissions_hub_module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "permissions-hub", +] + [[package]] name = "permissions_module" version = "0.0.0" diff --git a/pause-all/Cargo.toml b/pause-all/Cargo.toml index 6f03bfb68..b4ddeec43 100644 --- a/pause-all/Cargo.toml +++ b/pause-all/Cargo.toml @@ -26,3 +26,6 @@ path = "../dex/farm" [dev-dependencies.pair] path = "../dex/pair" + +[dev-dependencies.timestamp-oracle] +path = "../energy-integration/timestamp-oracle" diff --git a/pause-all/tests/pause_all_test.rs b/pause-all/tests/pause_all_test.rs index 0605891da..138987026 100644 --- a/pause-all/tests/pause_all_test.rs +++ b/pause-all/tests/pause_all_test.rs @@ -6,6 +6,7 @@ use multiversx_sc_scenario::{ use pair::Pair; use pausable::{PausableModule, State}; use pause_all::*; +use timestamp_oracle::{epoch_to_timestamp::EpochToTimestampModule, TimestampOracle}; static REWARD_TOKEN_ID: &[u8] = b"REWARD-123456"; static FARMING_TOKEN_ID: &[u8] = b"FARMING-123456"; @@ -16,6 +17,8 @@ static SECOND_TOKEN_ID: &[u8] = b"BEST-123456"; static TOTAL_FEE_PERCENT: u64 = 50; static SPECIAL_FEE_PERCENT: u64 = 50; +pub const TIMESTAMP_PER_EPOCH: u64 = 24 * 60 * 60; + #[test] fn pause_all_test() { let rust_zero = rust_biguint!(0u64); @@ -40,6 +43,27 @@ fn pause_all_test() { "output/pair.wasm", ); + let timestamp_oracle_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(&owner_address), + timestamp_oracle::contract_obj, + "timestamp oracle", + ); + b_mock + .execute_tx( + &owner_address, + ×tamp_oracle_wrapper, + &rust_zero, + |sc| { + sc.init(0); + + for i in 0..=21 { + sc.set_start_timestamp_for_epoch(i, i * TIMESTAMP_PER_EPOCH + 1); + } + }, + ) + .assert_ok(); + // init farm b_mock .execute_tx(&owner_address, &farm_sc, &rust_zero, |sc| { @@ -48,6 +72,7 @@ fn pause_all_test() { managed_token_id!(FARMING_TOKEN_ID), managed_biguint!(DIV_SAFETY), ManagedAddress::::zero(), + managed_address!(timestamp_oracle_wrapper.address_ref()), MultiValueEncoded::new(), );