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..2e53f39c5 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 @@ -38,16 +38,16 @@ pub trait BaseFarmInitModule: self.farming_token_id().set_if_empty(&farming_token_id); if !owner.is_zero() { - self.add_permissions(owner, Permissions::OWNER | Permissions::PAUSE); + self.add_permissions(&owner, Permissions::OWNER | Permissions::PAUSE); } let caller = self.blockchain().get_caller(); if admins.is_empty() { // backwards compatibility let all_permissions = Permissions::OWNER | Permissions::ADMIN | Permissions::PAUSE; - self.add_permissions(caller, all_permissions); + self.add_permissions(&caller, all_permissions); } else { - self.add_permissions(caller, Permissions::OWNER | Permissions::PAUSE); + self.add_permissions(&caller, Permissions::OWNER | Permissions::PAUSE); self.add_permissions_for_all(admins, Permissions::ADMIN); }; } diff --git a/common/modules/pausable/src/pausable.rs b/common/modules/pausable/src/pausable.rs index 6f8813685..5e4ad8ed5 100644 --- a/common/modules/pausable/src/pausable.rs +++ b/common/modules/pausable/src/pausable.rs @@ -26,7 +26,7 @@ pub trait PausableModule: permissions_module::PermissionsModule { self.require_caller_has_owner_permissions(); for address in address_list { - self.remove_permissions(address, Permissions::PAUSE); + self.remove_permissions(&address, Permissions::PAUSE); } } diff --git a/common/modules/permissions_module/src/permissions_module.rs b/common/modules/permissions_module/src/permissions_module.rs index 38eab7fdd..d9980c6d6 100644 --- a/common/modules/permissions_module/src/permissions_module.rs +++ b/common/modules/permissions_module/src/permissions_module.rs @@ -13,36 +13,36 @@ pub trait PermissionsModule { #[endpoint(addAdmin)] fn add_admin_endpoint(&self, address: ManagedAddress) { self.require_caller_has_owner_permissions(); - self.add_permissions(address, Permissions::ADMIN); + self.add_permissions(&address, Permissions::ADMIN); } #[endpoint(removeAdmin)] fn remove_admin_endpoint(&self, address: ManagedAddress) { self.require_caller_has_owner_permissions(); - self.remove_permissions(address, Permissions::ADMIN); + self.remove_permissions(&address, Permissions::ADMIN); } #[only_owner] #[endpoint(updateOwnerOrAdmin)] fn update_owner_or_admin_endpoint(&self, previous_owner: ManagedAddress) { let caller = self.blockchain().get_caller(); - let previous_owner_permissions = self.permissions(previous_owner.clone()).get(); + let previous_owner_permissions = self.permissions(&previous_owner).get(); - self.permissions(previous_owner).clear(); - self.permissions(caller).set(previous_owner_permissions); + self.permissions(&previous_owner).clear(); + self.permissions(&caller).set(previous_owner_permissions); } - fn set_permissions(&self, address: ManagedAddress, permissions: Permissions) { + fn set_permissions(&self, address: &ManagedAddress, permissions: Permissions) { self.permissions(address).set(permissions); } - fn add_permissions(&self, address: ManagedAddress, new_permissions: Permissions) { + fn add_permissions(&self, address: &ManagedAddress, new_permissions: Permissions) { self.permissions(address).update(|permissions| { permissions.insert(new_permissions); }); } - fn remove_permissions(&self, address: ManagedAddress, permissions_to_remove: Permissions) { + fn remove_permissions(&self, address: &ManagedAddress, permissions_to_remove: Permissions) { self.permissions(address).update(|permissions| { permissions.remove(permissions_to_remove); }); @@ -54,13 +54,13 @@ pub trait PermissionsModule { permissions: Permissions, ) { for address in addresses { - self.add_permissions(address, permissions.clone()); + self.add_permissions(&address, permissions.clone()); } } fn require_caller_any_of(&self, permissions: Permissions) { let caller = self.blockchain().get_caller(); - let caller_permissions = self.permissions(caller).get(); + let caller_permissions = self.permissions(&caller).get(); require!( caller_permissions.intersects(permissions), ERROR_PERMISSION_DENIED @@ -85,5 +85,5 @@ pub trait PermissionsModule { #[view(getPermissions)] #[storage_mapper("permissions")] - fn permissions(&self, address: ManagedAddress) -> SingleValueMapper; + fn permissions(&self, address: &ManagedAddress) -> SingleValueMapper; } diff --git a/dex/farm/tests/farm_multi_user_test.rs b/dex/farm/tests/farm_multi_user_test.rs index d37bee046..72db6521c 100644 --- a/dex/farm/tests/farm_multi_user_test.rs +++ b/dex/farm/tests/farm_multi_user_test.rs @@ -254,7 +254,7 @@ fn farm_change_boosted_yields_factors_test() { BoostedYieldsConfig::new(current_week - 1, default_factors.clone()); assert_eq!(expected_config, sc.boosted_yields_config().get()); - sc.add_permissions(managed_address!(&farm_addr), Permissions::all()); + sc.add_permissions(&managed_address!(&farm_addr), Permissions::all()); sc.set_boosted_yields_factors( managed_biguint!(1u64), managed_biguint!(1u64), diff --git a/dex/pair/src/fee/endpoints.rs b/dex/pair/src/fee/endpoints.rs new file mode 100644 index 000000000..ead9a99dc --- /dev/null +++ b/dex/pair/src/fee/endpoints.rs @@ -0,0 +1,138 @@ +use common_structs::{Percent, TokenPair}; + +use crate::{ + config::MAX_PERCENTAGE, ERROR_ALREADY_FEE_DEST, ERROR_ALREADY_WHITELISTED, + ERROR_BAD_TOKEN_FEE_DEST, ERROR_NOT_FEE_DEST, ERROR_NOT_WHITELISTED, + ERROR_PAIR_ALREADY_TRUSTED, ERROR_PAIR_NOT_TRUSTED, ERROR_SAME_TOKENS, +}; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait EndpointsModule: + crate::config::ConfigModule + + crate::liquidity_pool::LiquidityPoolModule + + crate::amm::AmmModule + + token_send::TokenSendModule + + permissions_module::PermissionsModule + + pausable::PausableModule + + super::storage::StorageModule +{ + #[endpoint(whitelist)] + fn whitelist_endpoint(&self, address: ManagedAddress) { + self.require_caller_has_owner_permissions(); + + let is_new = self.whitelist().insert(address); + require!(is_new, ERROR_ALREADY_WHITELISTED); + } + + #[endpoint(removeWhitelist)] + fn remove_whitelist(&self, address: ManagedAddress) { + self.require_caller_has_owner_permissions(); + + let is_removed = self.whitelist().remove(&address); + require!(is_removed, ERROR_NOT_WHITELISTED); + } + + #[endpoint(addTrustedSwapPair)] + fn add_trusted_swap_pair( + &self, + pair_address: ManagedAddress, + first_token: TokenIdentifier, + second_token: TokenIdentifier, + ) { + self.require_caller_has_owner_permissions(); + require!(first_token != second_token, ERROR_SAME_TOKENS); + + let token_pair = TokenPair { + first_token, + second_token, + }; + let is_new = self + .trusted_swap_pair() + .insert(token_pair, pair_address) + .is_none(); + require!(is_new, ERROR_PAIR_ALREADY_TRUSTED); + } + + #[endpoint(removeTrustedSwapPair)] + fn remove_trusted_swap_pair( + &self, + first_token: TokenIdentifier, + second_token: TokenIdentifier, + ) { + self.require_caller_has_owner_permissions(); + + let token_pair = TokenPair { + first_token: first_token.clone(), + second_token: second_token.clone(), + }; + + let mut is_removed = self.trusted_swap_pair().remove(&token_pair).is_some(); + if !is_removed { + let token_pair_reversed = TokenPair { + first_token: second_token, + second_token: first_token, + }; + is_removed = self + .trusted_swap_pair() + .remove(&token_pair_reversed) + .is_some(); + require!(is_removed, ERROR_PAIR_NOT_TRUSTED); + } + } + + /// `fees_collector_cut_percentage` of the special fees are sent to the fees_collector_address SC + /// + /// For example, if special fees is 5%, and fees_collector_cut_percentage is 10%, + /// then of the 5%, 10% are reserved, and only the rest are split between other pair contracts. + #[endpoint(setupFeesCollector)] + fn setup_fees_collector( + &self, + fees_collector_address: ManagedAddress, + fees_collector_cut_percentage: Percent, + ) { + self.require_caller_has_owner_permissions(); + require!( + self.blockchain().is_smart_contract(&fees_collector_address), + "Invalid fees collector address" + ); + require!( + fees_collector_cut_percentage > 0 && fees_collector_cut_percentage <= MAX_PERCENTAGE, + "Invalid fees percentage" + ); + + self.fees_collector_address().set(&fees_collector_address); + self.fees_collector_cut_percentage() + .set(fees_collector_cut_percentage); + } + + #[endpoint(setFeeOn)] + fn set_fee_on(&self, fee_to_address: ManagedAddress, fee_token: TokenIdentifier) { + self.require_caller_has_owner_permissions(); + + let is_dest = self + .destination_map() + .keys() + .any(|dest_address| dest_address == fee_to_address); + require!(!is_dest, ERROR_ALREADY_FEE_DEST); + + let _ = self.destination_map().insert(fee_to_address, fee_token); + } + + #[endpoint(setFeeOn)] + fn set_fee_off(&self, fee_to_address: ManagedAddress, fee_token: TokenIdentifier) { + self.require_caller_has_owner_permissions(); + + let is_dest = self + .destination_map() + .keys() + .any(|dest_address| dest_address == fee_to_address); + require!(is_dest, ERROR_NOT_FEE_DEST); + + let dest_fee_token = self.destination_map().get(&fee_to_address).unwrap(); + require!(fee_token == dest_fee_token, ERROR_BAD_TOKEN_FEE_DEST); + + let _ = self.destination_map().remove(&fee_to_address); + } +} diff --git a/dex/pair/src/fee.rs b/dex/pair/src/fee/impls.rs similarity index 57% rename from dex/pair/src/fee.rs rename to dex/pair/src/fee/impls.rs index 45df09f82..a7a93bc57 100644 --- a/dex/pair/src/fee.rs +++ b/dex/pair/src/fee/impls.rs @@ -1,17 +1,12 @@ -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); - -use super::amm; -use super::config; -use super::errors::*; -use super::liquidity_pool; -use crate::config::MAX_PERCENTAGE; -use crate::contexts::base::StorageCache; -use crate::contexts::base::SwapTokensOrder; - use common_structs::TokenPair; use fees_collector::fees_accumulation::ProxyTrait as _; +use crate::{ + config::MAX_PERCENTAGE, StorageCache, SwapTokensOrder, ERROR_NOTHING_TO_DO_WITH_FEE_SLICE, +}; + +multiversx_sc::imports!(); + mod self_proxy { multiversx_sc::imports!(); @@ -24,104 +19,15 @@ mod self_proxy { } #[multiversx_sc::module] -pub trait FeeModule: - config::ConfigModule - + liquidity_pool::LiquidityPoolModule - + amm::AmmModule +pub trait ImplsModule: + crate::config::ConfigModule + + crate::liquidity_pool::LiquidityPoolModule + + crate::amm::AmmModule + token_send::TokenSendModule + permissions_module::PermissionsModule + pausable::PausableModule + + super::storage::StorageModule { - #[view(getFeeState)] - fn is_fee_enabled(&self) -> bool { - !self.destination_map().is_empty() || !self.fees_collector_address().is_empty() - } - - #[endpoint(whitelist)] - fn whitelist_endpoint(&self, address: ManagedAddress) { - self.require_caller_has_owner_permissions(); - let is_new = self.whitelist().insert(address); - require!(is_new, ERROR_ALREADY_WHITELISTED); - } - - #[endpoint(removeWhitelist)] - fn remove_whitelist(&self, address: ManagedAddress) { - self.require_caller_has_owner_permissions(); - let is_removed = self.whitelist().remove(&address); - require!(is_removed, ERROR_NOT_WHITELISTED); - } - - #[endpoint(addTrustedSwapPair)] - fn add_trusted_swap_pair( - &self, - pair_address: ManagedAddress, - first_token: TokenIdentifier, - second_token: TokenIdentifier, - ) { - self.require_caller_has_owner_permissions(); - require!(first_token != second_token, ERROR_SAME_TOKENS); - let token_pair = TokenPair { - first_token, - second_token, - }; - let is_new = self - .trusted_swap_pair() - .insert(token_pair, pair_address) - .is_none(); - require!(is_new, ERROR_PAIR_ALREADY_TRUSTED); - } - - #[endpoint(removeTrustedSwapPair)] - fn remove_trusted_swap_pair( - &self, - first_token: TokenIdentifier, - second_token: TokenIdentifier, - ) { - self.require_caller_has_owner_permissions(); - let token_pair = TokenPair { - first_token: first_token.clone(), - second_token: second_token.clone(), - }; - - let mut is_removed = self.trusted_swap_pair().remove(&token_pair).is_some(); - if !is_removed { - let token_pair_reversed = TokenPair { - first_token: second_token, - second_token: first_token, - }; - is_removed = self - .trusted_swap_pair() - .remove(&token_pair_reversed) - .is_some(); - require!(is_removed, ERROR_PAIR_NOT_TRUSTED); - } - } - - /// `fees_collector_cut_percentage` of the special fees are sent to the fees_collector_address SC - /// - /// For example, if special fees is 5%, and fees_collector_cut_percentage is 10%, - /// then of the 5%, 10% are reserved, and only the rest are split between other pair contracts. - #[endpoint(setupFeesCollector)] - fn setup_fees_collector( - &self, - fees_collector_address: ManagedAddress, - fees_collector_cut_percentage: u64, - ) { - self.require_caller_has_owner_permissions(); - require!( - self.blockchain().is_smart_contract(&fees_collector_address), - "Invalid fees collector address" - ); - require!( - fees_collector_cut_percentage > 0 && fees_collector_cut_percentage <= MAX_PERCENTAGE, - "Invalid fees percentage" - ); - - self.fees_collector_address().set(&fees_collector_address); - self.fees_collector_cut_percentage() - .set(fees_collector_cut_percentage); - } - fn send_fee( &self, storage_cache: &mut StorageCache, @@ -304,13 +210,6 @@ pub trait FeeModule: .execute_on_dest_context(); } - #[inline] - fn burn(&self, token: &TokenIdentifier, amount: &BigUint) { - if amount > &0 { - self.send().esdt_local_burn(token, 0, amount); - } - } - fn get_extern_swap_pair_address( &self, first_token: &TokenIdentifier, @@ -346,55 +245,11 @@ pub trait FeeModule: } } - #[endpoint(setFeeOn)] - fn set_fee_on( - &self, - enabled: bool, - fee_to_address: ManagedAddress, - fee_token: TokenIdentifier, - ) { - self.require_caller_has_owner_permissions(); - let is_dest = self - .destination_map() - .keys() - .any(|dest_address| dest_address == fee_to_address); - - if enabled { - require!(!is_dest, ERROR_ALREADY_FEE_DEST); - self.destination_map().insert(fee_to_address, fee_token); - } else { - require!(is_dest, ERROR_NOT_FEE_DEST); - let dest_fee_token = self.destination_map().get(&fee_to_address).unwrap(); - require!(fee_token == dest_fee_token, ERROR_BAD_TOKEN_FEE_DEST); - self.destination_map().remove(&fee_to_address); - } - } - - #[view(getFeeDestinations)] - fn get_fee_destinations(&self) -> MultiValueEncoded<(ManagedAddress, TokenIdentifier)> { - let mut result = MultiValueEncoded::new(); - for pair in self.destination_map().iter() { - result.push((pair.0, pair.1)) - } - result - } - - #[view(getTrustedSwapPairs)] - fn get_trusted_swap_pairs(&self) -> MultiValueEncoded<(TokenPair, ManagedAddress)> { - let mut result = MultiValueEncoded::new(); - for pair in self.trusted_swap_pair().iter() { - result.push((pair.0, pair.1)) - } - result - } - - #[view(getWhitelistedManagedAddresses)] - fn get_whitelisted_managed_addresses(&self) -> MultiValueEncoded { - let mut result = MultiValueEncoded::new(); - for pair in self.whitelist().iter() { - result.push(pair); + #[inline] + fn burn(&self, token: &TokenIdentifier, amount: &BigUint) { + if amount > &0 { + self.send().esdt_local_burn(token, 0, amount); } - result } #[proxy] @@ -402,21 +257,4 @@ pub trait FeeModule: #[proxy] fn fees_collector_proxy(&self, sc_address: ManagedAddress) -> fees_collector::Proxy; - - #[view(getFeesCollectorAddress)] - #[storage_mapper("feesCollectorAddress")] - fn fees_collector_address(&self) -> SingleValueMapper; - - #[view(getFeesCollectorCutPercentage)] - #[storage_mapper("feesCollectorCutPercentage")] - fn fees_collector_cut_percentage(&self) -> SingleValueMapper; - - #[storage_mapper("fee_destination")] - fn destination_map(&self) -> MapMapper; - - #[storage_mapper("trusted_swap_pair")] - fn trusted_swap_pair(&self) -> MapMapper, ManagedAddress>; - - #[storage_mapper("whitelist")] - fn whitelist(&self) -> SetMapper; } diff --git a/dex/pair/src/fee/mod.rs b/dex/pair/src/fee/mod.rs new file mode 100644 index 000000000..9f7633315 --- /dev/null +++ b/dex/pair/src/fee/mod.rs @@ -0,0 +1,4 @@ +pub mod endpoints; +pub mod impls; +pub mod storage; +pub mod views; diff --git a/dex/pair/src/fee/storage.rs b/dex/pair/src/fee/storage.rs new file mode 100644 index 000000000..9da4384d3 --- /dev/null +++ b/dex/pair/src/fee/storage.rs @@ -0,0 +1,23 @@ +use common_structs::{Percent, TokenPair}; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait StorageModule { + #[view(getFeesCollectorAddress)] + #[storage_mapper("feesCollectorAddress")] + fn fees_collector_address(&self) -> SingleValueMapper; + + #[view(getFeesCollectorCutPercentage)] + #[storage_mapper("feesCollectorCutPercentage")] + fn fees_collector_cut_percentage(&self) -> SingleValueMapper; + + #[storage_mapper("fee_destination")] + fn destination_map(&self) -> MapMapper; + + #[storage_mapper("trusted_swap_pair")] + fn trusted_swap_pair(&self) -> MapMapper, ManagedAddress>; + + #[storage_mapper("whitelist")] + fn whitelist(&self) -> SetMapper; +} diff --git a/dex/pair/src/fee/views.rs b/dex/pair/src/fee/views.rs new file mode 100644 index 000000000..8f82397af --- /dev/null +++ b/dex/pair/src/fee/views.rs @@ -0,0 +1,41 @@ +use common_structs::TokenPair; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait ViewsModule: super::storage::StorageModule { + #[view(getFeeState)] + fn is_fee_enabled(&self) -> bool { + !self.destination_map().is_empty() || !self.fees_collector_address().is_empty() + } + + #[view(getFeeDestinations)] + fn get_fee_destinations(&self) -> MultiValueEncoded<(ManagedAddress, TokenIdentifier)> { + let mut result = MultiValueEncoded::new(); + for pair in self.destination_map().iter() { + result.push((pair.0, pair.1)) + } + + result + } + + #[view(getTrustedSwapPairs)] + fn get_trusted_swap_pairs(&self) -> MultiValueEncoded<(TokenPair, ManagedAddress)> { + let mut result = MultiValueEncoded::new(); + for pair in self.trusted_swap_pair().iter() { + result.push((pair.0, pair.1)) + } + + result + } + + #[view(getWhitelistedManagedAddresses)] + fn get_whitelisted_managed_addresses(&self) -> MultiValueEncoded { + let mut result = MultiValueEncoded::new(); + for pair in self.whitelist().iter() { + result.push(pair); + } + + result + } +} diff --git a/dex/pair/src/lib.rs b/dex/pair/src/lib.rs index e67010d67..9d4f806a0 100644 --- a/dex/pair/src/lib.rs +++ b/dex/pair/src/lib.rs @@ -29,7 +29,10 @@ use permissions_module::Permissions; #[multiversx_sc::contract] pub trait Pair: amm::AmmModule - + fee::FeeModule + + fee::endpoints::EndpointsModule + + fee::impls::ImplsModule + + fee::storage::StorageModule + + fee::views::ViewsModule + liquidity_pool::LiquidityPoolModule + config::ConfigModule + token_send::TokenSendModule @@ -76,25 +79,26 @@ pub trait Pair: self.state().set(State::Inactive); self.router_address().set(&router_address); - self.first_token_id().set_if_empty(&first_token_id); - self.second_token_id().set_if_empty(&second_token_id); - let initial_liquidity_adder_opt = if !initial_liquidity_adder.is_zero() { + self.first_token_id().set(first_token_id); + self.second_token_id().set(second_token_id); + + let opt_initial_liquidity_adder = if !initial_liquidity_adder.is_zero() { Some(initial_liquidity_adder) } else { None }; self.initial_liquidity_adder() - .set_if_empty(&initial_liquidity_adder_opt); + .set(&opt_initial_liquidity_adder); if admins.is_empty() { // backwards compatibility let all_permissions = Permissions::OWNER | Permissions::ADMIN | Permissions::PAUSE; - self.add_permissions(router_address, all_permissions.clone()); - self.add_permissions(router_owner_address, all_permissions); + self.add_permissions(&router_address, all_permissions.clone()); + self.add_permissions(&router_owner_address, all_permissions); } else { - self.add_permissions(router_address, Permissions::OWNER | Permissions::PAUSE); + self.add_permissions(&router_address, Permissions::OWNER | Permissions::PAUSE); self.add_permissions( - router_owner_address, + &router_owner_address, Permissions::OWNER | Permissions::PAUSE, ); self.add_permissions_for_all(admins, Permissions::ADMIN); @@ -121,6 +125,7 @@ pub trait Pair: token_identifier.is_valid_esdt_identifier(), ERROR_NOT_AN_ESDT ); + self.lp_token_identifier().set(&token_identifier); } } diff --git a/dex/pair/src/pair_actions/remove_liq.rs b/dex/pair/src/pair_actions/remove_liq.rs index 1010ac666..5b8dd5ff1 100644 --- a/dex/pair/src/pair_actions/remove_liq.rs +++ b/dex/pair/src/pair_actions/remove_liq.rs @@ -16,7 +16,10 @@ pub trait RemoveLiquidityModule: + crate::locking_wrapper::LockingWrapperModule + crate::events::EventsModule + crate::safe_price::SafePriceModule - + crate::fee::FeeModule + + crate::fee::endpoints::EndpointsModule + + crate::fee::impls::ImplsModule + + crate::fee::storage::StorageModule + + crate::fee::views::ViewsModule + crate::config::ConfigModule + token_send::TokenSendModule + permissions_module::PermissionsModule diff --git a/dex/pair/src/pair_actions/swap.rs b/dex/pair/src/pair_actions/swap.rs index 62cdc01d4..161a05f05 100644 --- a/dex/pair/src/pair_actions/swap.rs +++ b/dex/pair/src/pair_actions/swap.rs @@ -23,7 +23,10 @@ pub trait SwapModule: + crate::locking_wrapper::LockingWrapperModule + crate::events::EventsModule + crate::safe_price::SafePriceModule - + crate::fee::FeeModule + + crate::fee::endpoints::EndpointsModule + + crate::fee::impls::ImplsModule + + crate::fee::storage::StorageModule + + crate::fee::views::ViewsModule + crate::config::ConfigModule + token_send::TokenSendModule + permissions_module::PermissionsModule diff --git a/dex/pair/src/pair_actions/views.rs b/dex/pair/src/pair_actions/views.rs index 878b3bd5e..a90f3d79f 100644 --- a/dex/pair/src/pair_actions/views.rs +++ b/dex/pair/src/pair_actions/views.rs @@ -10,7 +10,10 @@ pub trait ViewsModule: + crate::locking_wrapper::LockingWrapperModule + crate::events::EventsModule + crate::safe_price::SafePriceModule - + crate::fee::FeeModule + + crate::fee::endpoints::EndpointsModule + + crate::fee::impls::ImplsModule + + crate::fee::storage::StorageModule + + crate::fee::views::ViewsModule + crate::config::ConfigModule + token_send::TokenSendModule + permissions_module::PermissionsModule diff --git a/dex/pair/tests/pair_rs_test.rs b/dex/pair/tests/pair_rs_test.rs index bd82750d8..3d5d88202 100644 --- a/dex/pair/tests/pair_rs_test.rs +++ b/dex/pair/tests/pair_rs_test.rs @@ -19,9 +19,9 @@ use multiversx_sc_scenario::{ managed_address, managed_biguint, managed_token_id, managed_token_id_wrapped, rust_biguint, whitebox_legacy::TxTokenTransfer, DebugApi, }; +use pair::fee::endpoints::EndpointsModule; use pair::{ config::MAX_PERCENTAGE, - fee::FeeModule, locking_wrapper::LockingWrapperModule, pair_actions::swap::SwapModule, safe_price::{PriceObservation, Round, SafePriceModule}, diff --git a/dex/pair/wasm-pair-full/src/lib.rs b/dex/pair/wasm-pair-full/src/lib.rs index 5f39165a9..c5f8b252a 100644 --- a/dex/pair/wasm-pair-full/src/lib.rs +++ b/dex/pair/wasm-pair-full/src/lib.rs @@ -21,18 +21,18 @@ multiversx_sc_wasm_adapter::endpoints! { init => init upgrade => upgrade setLpTokenIdentifier => set_lp_token_identifier - getFeeState => is_fee_enabled whitelist => whitelist_endpoint removeWhitelist => remove_whitelist addTrustedSwapPair => add_trusted_swap_pair removeTrustedSwapPair => remove_trusted_swap_pair setupFeesCollector => setup_fees_collector setFeeOn => set_fee_on + getFeesCollectorAddress => fees_collector_address + getFeesCollectorCutPercentage => fees_collector_cut_percentage + getFeeState => is_fee_enabled getFeeDestinations => get_fee_destinations getTrustedSwapPairs => get_trusted_swap_pairs getWhitelistedManagedAddresses => get_whitelisted_managed_addresses - getFeesCollectorAddress => fees_collector_address - getFeesCollectorCutPercentage => fees_collector_cut_percentage setStateActiveNoSwaps => set_state_active_no_swaps setFeePercents => set_fee_percent getLpTokenIdentifier => get_lp_token_identifier diff --git a/dex/pair/wasm/src/lib.rs b/dex/pair/wasm/src/lib.rs index 7279213ee..99d1687f7 100644 --- a/dex/pair/wasm/src/lib.rs +++ b/dex/pair/wasm/src/lib.rs @@ -21,18 +21,18 @@ multiversx_sc_wasm_adapter::endpoints! { init => init upgrade => upgrade setLpTokenIdentifier => set_lp_token_identifier - getFeeState => is_fee_enabled whitelist => whitelist_endpoint removeWhitelist => remove_whitelist addTrustedSwapPair => add_trusted_swap_pair removeTrustedSwapPair => remove_trusted_swap_pair setupFeesCollector => setup_fees_collector setFeeOn => set_fee_on + getFeesCollectorAddress => fees_collector_address + getFeesCollectorCutPercentage => fees_collector_cut_percentage + getFeeState => is_fee_enabled getFeeDestinations => get_fee_destinations getTrustedSwapPairs => get_trusted_swap_pairs getWhitelistedManagedAddresses => get_whitelisted_managed_addresses - getFeesCollectorAddress => fees_collector_address - getFeesCollectorCutPercentage => fees_collector_cut_percentage setStateActiveNoSwaps => set_state_active_no_swaps setFeePercents => set_fee_percent getLpTokenIdentifier => get_lp_token_identifier diff --git a/dex/router/src/config.rs b/dex/router/src/config.rs index 105765bca..e8ce1b1d9 100644 --- a/dex/router/src/config.rs +++ b/dex/router/src/config.rs @@ -4,18 +4,28 @@ multiversx_sc::derive_imports!(); use crate::pair_actions::create::PairTokens; use pair::read_pair_storage; +pub type PairCreationStatus = bool; +pub const ENABLED: PairCreationStatus = true; +pub const DISABLED: PairCreationStatus = false; + #[multiversx_sc::module] pub trait ConfigModule: read_pair_storage::ReadPairStorageModule { #[only_owner] #[endpoint(setPairTemplateAddress)] fn set_pair_template_address(&self, address: ManagedAddress) { - self.pair_template_address().set(&address); + self.pair_template_address().set(address); } #[only_owner] #[endpoint(setPairCreationEnabled)] - fn set_pair_creation_enabled(&self, enabled: bool) { - self.pair_creation_enabled().set(enabled); + fn set_pair_creation_enabled(&self) { + self.pair_creation_enabled().set(ENABLED); + } + + #[only_owner] + #[endpoint(setPairCreationDisabled)] + fn set_pair_creation_disabled(&self) { + self.pair_creation_enabled().set(DISABLED); } fn check_is_pair_sc(&self, pair_address: &ManagedAddress) { @@ -38,15 +48,20 @@ pub trait ConfigModule: read_pair_storage::ReadPairStorageModule { require!(pair_map_address_opt.is_some(), "Not a pair SC"); - unsafe { - let pair_map_address = pair_map_address_opt.unwrap_unchecked(); - require!(&pair_map_address == pair_address, "Not a pair SC"); - } + let pair_map_address = unsafe { pair_map_address_opt.unwrap_unchecked() }; + require!(&pair_map_address == pair_address, "Not a pair SC"); + } + + fn require_pair_creation_enabled(&self) { + require!( + self.pair_creation_enabled().get() == ENABLED, + "Pair creation is disabled" + ); } #[view(getPairCreationEnabled)] #[storage_mapper("pair_creation_enabled")] - fn pair_creation_enabled(&self) -> SingleValueMapper; + fn pair_creation_enabled(&self) -> SingleValueMapper; #[view(getOwner)] #[storage_mapper("owner")] diff --git a/dex/router/src/events.rs b/dex/router/src/events.rs index a06899e6b..f26343d08 100644 --- a/dex/router/src/events.rs +++ b/dex/router/src/events.rs @@ -6,34 +6,34 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); #[derive(TypeAbi, TopEncode)] -pub struct CreatePairEvent { - caller: ManagedAddress, - first_token_id: TokenIdentifier, - second_token_id: TokenIdentifier, +pub struct CreatePairEvent<'a, M: ManagedTypeApi> { + caller: &'a ManagedAddress, + first_token_id: &'a TokenIdentifier, + second_token_id: &'a TokenIdentifier, total_fee_percent: Percent, special_fee_percent: Percent, - pair_address: ManagedAddress, + pair_address: &'a ManagedAddress, block: Blocks, epoch: Epoch, timestamp: u64, } #[derive(TypeAbi, TopEncode)] -pub struct UserPairSwapEnabledEvent { - caller: ManagedAddress, - first_token_id: TokenIdentifier, - second_token_id: TokenIdentifier, - pair_address: ManagedAddress, +pub struct UserPairSwapEnabledEvent<'a, M: ManagedTypeApi> { + caller: &'a ManagedAddress, + first_token_id: &'a TokenIdentifier, + second_token_id: &'a TokenIdentifier, + pair_address: &'a ManagedAddress, } #[derive(TypeAbi, TopEncode)] -pub struct MultiPairSwapEvent { - caller: ManagedAddress, - token_in: TokenIdentifier, - amount_in: BigUint, - token_out: TokenIdentifier, - amount_out: BigUint, - payments_out: ManagedVec>, +pub struct MultiPairSwapEvent<'a, M: ManagedTypeApi> { + caller: &'a ManagedAddress, + token_in: &'a TokenIdentifier, + amount_in: &'a BigUint, + token_out: &'a TokenIdentifier, + amount_out: &'a BigUint, + payments_out: &'a ManagedVec>, block: Blocks, epoch: Epoch, timestamp: u64, @@ -43,18 +43,18 @@ pub struct MultiPairSwapEvent { pub trait EventsModule { fn emit_create_pair_event( self, - caller: ManagedAddress, - first_token_id: TokenIdentifier, - second_token_id: TokenIdentifier, + caller: &ManagedAddress, + first_token_id: &TokenIdentifier, + second_token_id: &TokenIdentifier, total_fee_percent: Percent, special_fee_percent: Percent, - pair_address: ManagedAddress, + pair_address: &ManagedAddress, ) { let epoch = self.blockchain().get_block_epoch(); self.create_pair_event( - first_token_id.clone(), - second_token_id.clone(), - caller.clone(), + first_token_id, + second_token_id, + caller, epoch, CreatePairEvent { caller, @@ -72,16 +72,16 @@ pub trait EventsModule { fn emit_user_swaps_enabled_event( &self, - caller: ManagedAddress, - first_token_id: TokenIdentifier, - second_token_id: TokenIdentifier, - pair_address: ManagedAddress, + caller: &ManagedAddress, + first_token_id: &TokenIdentifier, + second_token_id: &TokenIdentifier, + pair_address: &ManagedAddress, ) { let epoch = self.blockchain().get_block_epoch(); self.pair_swap_enabled_event( - first_token_id.clone(), - second_token_id.clone(), - caller.clone(), + first_token_id, + second_token_id, + caller, epoch, UserPairSwapEnabledEvent { caller, @@ -94,10 +94,10 @@ pub trait EventsModule { fn emit_multi_pair_swap_event( &self, - caller: ManagedAddress, - token_in: TokenIdentifier, - amount_in: BigUint, - payments_out: ManagedVec, + caller: &ManagedAddress, + token_in: &TokenIdentifier, + amount_in: &BigUint, + payments_out: &ManagedVec, ) { if payments_out.is_empty() { return; @@ -109,18 +109,18 @@ pub trait EventsModule { let last_payment_index = payments_out.len() - 1; let token_out = payments_out.get(last_payment_index); self.multi_pair_swap_event( - caller.clone(), - token_in.clone(), - amount_in.clone(), - token_out.token_identifier.clone(), - token_out.amount.clone(), + caller, + token_in, + amount_in, + &token_out.token_identifier, + &token_out.amount, epoch, MultiPairSwapEvent { caller, token_in, amount_in, - token_out: token_out.token_identifier, - amount_out: token_out.amount, + token_out: &token_out.token_identifier, + amount_out: &token_out.amount, payments_out, block, epoch, @@ -132,9 +132,9 @@ pub trait EventsModule { #[event("create_pair")] fn create_pair_event( self, - #[indexed] first_token_id: TokenIdentifier, - #[indexed] second_token_id: TokenIdentifier, - #[indexed] caller: ManagedAddress, + #[indexed] first_token_id: &TokenIdentifier, + #[indexed] second_token_id: &TokenIdentifier, + #[indexed] caller: &ManagedAddress, #[indexed] epoch: Epoch, swap_event: CreatePairEvent, ); @@ -142,9 +142,9 @@ pub trait EventsModule { #[event("pairSwapEnabled")] fn pair_swap_enabled_event( &self, - #[indexed] first_token_id: TokenIdentifier, - #[indexed] second_token_id: TokenIdentifier, - #[indexed] caller: ManagedAddress, + #[indexed] first_token_id: &TokenIdentifier, + #[indexed] second_token_id: &TokenIdentifier, + #[indexed] caller: &ManagedAddress, #[indexed] epoch: Epoch, swap_enabled_event: UserPairSwapEnabledEvent, ); @@ -152,11 +152,11 @@ pub trait EventsModule { #[event("multiPairSwap")] fn multi_pair_swap_event( &self, - #[indexed] caller: ManagedAddress, - #[indexed] token_in: TokenIdentifier, - #[indexed] amount_in: BigUint, - #[indexed] token_out: TokenIdentifier, - #[indexed] amount_out: BigUint, + #[indexed] caller: &ManagedAddress, + #[indexed] token_in: &TokenIdentifier, + #[indexed] amount_in: &BigUint, + #[indexed] token_out: &TokenIdentifier, + #[indexed] amount_out: &BigUint, #[indexed] epoch: Epoch, multi_pair_swap_event: MultiPairSwapEvent, ); diff --git a/dex/router/src/lib.rs b/dex/router/src/lib.rs index aeba7cc14..d12248ee7 100644 --- a/dex/router/src/lib.rs +++ b/dex/router/src/lib.rs @@ -10,6 +10,7 @@ pub mod state; pub mod temp_owner; pub mod views; +use config::DISABLED; use pair::read_pair_storage; use state::{ACTIVE, INACTIVE}; @@ -24,6 +25,7 @@ pub trait Router: + events::EventsModule + token_send::TokenSendModule + pair_actions::enable_swap_by_user::EnableSwapByUserModule + + pair_actions::enable_buyback_and_burn::EnableBuybackAndBurnModule + pair_actions::multi_pair_swap::MultiPairSwap + pair_actions::create::CreateModule + pair_actions::upgrade::UpgradeModule @@ -35,10 +37,15 @@ pub trait Router: + views::ViewsModule { #[init] - fn init(&self, pair_template_address_opt: OptionalValue) { - self.state().set(ACTIVE); - self.pair_creation_enabled().set(false); + fn init( + &self, + token_to_buy: TokenIdentifier, + pair_template_address_opt: OptionalValue, + ) { + self.set_token_to_buy(token_to_buy); + self.state().set(ACTIVE); + self.pair_creation_enabled().set(DISABLED); self.temporary_owner_period() .set(DEFAULT_TEMPORARY_OWNER_PERIOD_BLOCKS); @@ -46,7 +53,8 @@ pub trait Router: self.pair_template_address().set(&addr); } - self.owner().set(&self.blockchain().get_caller()); + let caller = self.blockchain().get_caller(); + self.owner().set(caller); } #[upgrade] diff --git a/dex/router/src/pair_actions/create.rs b/dex/router/src/pair_actions/create.rs index 61893f003..c552942e9 100644 --- a/dex/router/src/pair_actions/create.rs +++ b/dex/router/src/pair_actions/create.rs @@ -24,6 +24,13 @@ pub const DEFAULT_SPECIAL_FEE_PERCENT: Percent = 50; pub const MAX_TOTAL_FEE_PERCENT: Percent = 100_000; pub const USER_DEFINED_TOTAL_FEE_PERCENT: Percent = 1_000; +pub type FeePercentArgType = OptionalValue>; + +pub struct FeePercentResult { + pub total_fee_percent_requested: Percent, + pub special_fee_percent_requested: Percent, +} + #[multiversx_sc::module] pub trait CreateModule: crate::config::ConfigModule @@ -40,7 +47,7 @@ pub trait CreateModule: first_token_id: TokenIdentifier, second_token_id: TokenIdentifier, initial_liquidity_adder: ManagedAddress, - opt_fee_percents: OptionalValue>, + opt_fee_percents: FeePercentArgType, mut admins: MultiValueEncoded, ) -> ManagedAddress { self.require_active(); @@ -48,10 +55,7 @@ pub trait CreateModule: let owner = self.owner().get(); let caller = self.blockchain().get_caller(); if caller != owner { - require!( - self.pair_creation_enabled().get(), - "Pair creation is disabled" - ); + self.require_pair_creation_enabled(); } require!(first_token_id != second_token_id, "Identical tokens"); @@ -67,24 +71,16 @@ pub trait CreateModule: let pair_address = self.get_pair(first_token_id.clone(), second_token_id.clone()); require!(pair_address.is_zero(), "Pair already exists"); - let mut total_fee_percent_requested = DEFAULT_TOTAL_FEE_PERCENT; - let mut special_fee_percent_requested = DEFAULT_SPECIAL_FEE_PERCENT; - if caller == owner { - match opt_fee_percents { - OptionalValue::Some(fee_percents_multi_arg) => { - let fee_percents_tuple = fee_percents_multi_arg.into_tuple(); - total_fee_percent_requested = fee_percents_tuple.0; - special_fee_percent_requested = fee_percents_tuple.1; - - require!( - total_fee_percent_requested >= special_fee_percent_requested - && total_fee_percent_requested < MAX_TOTAL_FEE_PERCENT, - "Bad percents" - ); - } - OptionalValue::None => sc_panic!("Bad percents length"), - } - } + let (total_fee_percent_requested, special_fee_percent_requested) = if caller == owner { + let fee_percents = self.get_owner_set_fee_percents(opt_fee_percents); + + ( + fee_percents.total_fee_percent_requested, + fee_percents.special_fee_percent_requested, + ) + } else { + (DEFAULT_TOTAL_FEE_PERCENT, DEFAULT_SPECIAL_FEE_PERCENT) + }; admins.push(caller.clone()); @@ -99,17 +95,38 @@ pub trait CreateModule: }); self.emit_create_pair_event( - caller, - first_token_id, - second_token_id, + &caller, + &first_token_id, + &second_token_id, total_fee_percent_requested, special_fee_percent_requested, - address.clone(), + &address, ); address } + fn get_owner_set_fee_percents(&self, opt_fee_percents: FeePercentArgType) -> FeePercentResult { + match opt_fee_percents { + OptionalValue::Some(fee_percents_multi_arg) => { + let fee_percents_tuple = fee_percents_multi_arg.into_tuple(); + let total_fee_percent_requested = fee_percents_tuple.0; + let special_fee_percent_requested = fee_percents_tuple.1; + require!( + total_fee_percent_requested >= special_fee_percent_requested + && total_fee_percent_requested < MAX_TOTAL_FEE_PERCENT, + "Bad percents" + ); + + FeePercentResult { + total_fee_percent_requested, + special_fee_percent_requested, + } + } + OptionalValue::None => sc_panic!("Bad percents length"), + } + } + fn create_pair(&self, args: CreatePairArgs) -> ManagedAddress { require!( !self.pair_template_address().is_empty(), diff --git a/dex/router/src/pair_actions/enable_buyback_and_burn.rs b/dex/router/src/pair_actions/enable_buyback_and_burn.rs new file mode 100644 index 000000000..ee8558aaf --- /dev/null +++ b/dex/router/src/pair_actions/enable_buyback_and_burn.rs @@ -0,0 +1,78 @@ +use pair::fee::endpoints::ProxyTrait as _; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait EnableBuybackAndBurnModule: + crate::config::ConfigModule + + pair::read_pair_storage::ReadPairStorageModule + + crate::views::ViewsModule +{ + #[only_owner] + #[endpoint(setTokenToBuy)] + fn set_token_to_buy(&self, token_to_buy: TokenIdentifier) { + require!( + token_to_buy.is_valid_esdt_identifier(), + "Invalid token to buy" + ); + + self.token_to_buy().set(token_to_buy); + } + + fn enable_buyback_and_burn(&self, pair_address: ManagedAddress) { + let first_token_id = self.get_first_token_id_mapper(pair_address.clone()).get(); + let second_token_id = self.get_second_token_id_mapper(pair_address.clone()).get(); + let common_tokens_mapper = self.common_tokens_for_user_pairs(); + let common_token_id = if common_tokens_mapper.contains(&first_token_id) { + first_token_id + } else if common_tokens_mapper.contains(&second_token_id) { + second_token_id + } else { + return; + }; + + let token_to_buy = self.token_to_buy().get(); + let found_pair = self.get_pair(token_to_buy.clone(), common_token_id); + if found_pair.is_zero() { + return; + } + + self.whitelist_in_found_pair(found_pair.clone(), pair_address.clone()); + self.add_trusted_swap_current_pair(found_pair.clone(), pair_address.clone()); + self.set_fee_on_pair(pair_address, token_to_buy); + } + + fn whitelist_in_found_pair(&self, found_pair: ManagedAddress, current_pair: ManagedAddress) { + self.pair_contract_proxy_buyback(found_pair) + .whitelist_endpoint(current_pair) + .execute_on_dest_context() + } + + fn add_trusted_swap_current_pair( + &self, + found_pair: ManagedAddress, + current_pair: ManagedAddress, + ) { + let first_token_id_found_pair = self.get_first_token_id_mapper(found_pair.clone()).get(); + let second_token_id_found_pair = self.get_second_token_id_mapper(found_pair.clone()).get(); + self.pair_contract_proxy_buyback(current_pair) + .add_trusted_swap_pair( + found_pair, + first_token_id_found_pair, + second_token_id_found_pair, + ) + .execute_on_dest_context() + } + + fn set_fee_on_pair(&self, current_pair: ManagedAddress, fee_token_id: TokenIdentifier) { + self.pair_contract_proxy_buyback(current_pair) + .set_fee_on(ManagedAddress::zero(), fee_token_id) + .execute_on_dest_context() + } + + #[proxy] + fn pair_contract_proxy_buyback(&self, to: ManagedAddress) -> pair::Proxy; + + #[storage_mapper("tokenToBuy")] + fn token_to_buy(&self) -> SingleValueMapper; +} diff --git a/dex/router/src/pair_actions/enable_swap_by_user.rs b/dex/router/src/pair_actions/enable_swap_by_user.rs index b9c1ed713..88887e869 100644 --- a/dex/router/src/pair_actions/enable_swap_by_user.rs +++ b/dex/router/src/pair_actions/enable_swap_by_user.rs @@ -32,6 +32,8 @@ pub trait EnableSwapByUserModule: + read_pair_storage::ReadPairStorageModule + crate::events::EventsModule + crate::state::StateModule + + super::enable_buyback_and_burn::EnableBuybackAndBurnModule + + crate::views::ViewsModule { #[only_owner] #[endpoint(configEnableByUserParameters)] @@ -81,7 +83,8 @@ pub trait EnableSwapByUserModule: fn remove_common_tokens_for_user_pairs(&self, tokens: MultiValueEncoded) { let mut whitelist = self.common_tokens_for_user_pairs(); for token in tokens { - let _ = whitelist.swap_remove(&token); + let removed = whitelist.swap_remove(&token); + require!(removed, "Token not present in whitelist"); } } @@ -138,6 +141,7 @@ pub trait EnableSwapByUserModule: self.set_fee_percents(pair_address.clone()); self.pair_resume(pair_address.clone()); + self.enable_buyback_and_burn(pair_address.clone()); self.send().direct_esdt( &caller, @@ -147,10 +151,10 @@ pub trait EnableSwapByUserModule: ); self.emit_user_swaps_enabled_event( - caller, - lp_token_safe_price_result.first_token_id, - lp_token_safe_price_result.second_token_id, - pair_address, + &caller, + &lp_token_safe_price_result.first_token_id, + &lp_token_safe_price_result.second_token_id, + &pair_address, ); } @@ -190,6 +194,7 @@ pub trait EnableSwapByUserModule: common_token_id: first_result.token_identifier, safe_price_in_common_token: BigUint::zero(), }; + let whitelist = self.common_tokens_for_user_pairs(); if whitelist.contains(&safe_price_result.first_token_id) { safe_price_result.safe_price_in_common_token = first_result.amount; diff --git a/dex/router/src/pair_actions/fees.rs b/dex/router/src/pair_actions/fees.rs index d301b80c9..fe248d73c 100644 --- a/dex/router/src/pair_actions/fees.rs +++ b/dex/router/src/pair_actions/fees.rs @@ -1,4 +1,4 @@ -use pair::fee::ProxyTrait as _; +use pair::fee::endpoints::ProxyTrait as _; multiversx_sc::imports!(); @@ -20,10 +20,9 @@ pub trait FeesModule: self.require_active(); self.check_is_pair_sc(&pair_address); - let _: IgnoreValue = self - .pair_contract_proxy_fees(pair_address) - .set_fee_on(true, fee_to_address, fee_token) - .execute_on_dest_context(); + self.pair_contract_proxy_fees(pair_address) + .set_fee_on(fee_to_address, fee_token) + .execute_on_dest_context() } #[only_owner] @@ -37,10 +36,9 @@ pub trait FeesModule: self.require_active(); self.check_is_pair_sc(&pair_address); - let _: IgnoreValue = self - .pair_contract_proxy_fees(pair_address) - .set_fee_on(false, fee_to_address, fee_token) - .execute_on_dest_context(); + self.pair_contract_proxy_fees(pair_address) + .set_fee_off(fee_to_address, fee_token) + .execute_on_dest_context() } #[proxy] diff --git a/dex/router/src/pair_actions/mod.rs b/dex/router/src/pair_actions/mod.rs index 2ef1ff893..82dd4e573 100644 --- a/dex/router/src/pair_actions/mod.rs +++ b/dex/router/src/pair_actions/mod.rs @@ -1,4 +1,5 @@ pub mod create; +pub mod enable_buyback_and_burn; pub mod enable_swap_by_user; pub mod fees; pub mod multi_pair_swap; diff --git a/dex/router/src/pair_actions/multi_pair_swap.rs b/dex/router/src/pair_actions/multi_pair_swap.rs index 2d7368217..c800531d0 100644 --- a/dex/router/src/pair_actions/multi_pair_swap.rs +++ b/dex/router/src/pair_actions/multi_pair_swap.rs @@ -88,7 +88,7 @@ pub trait MultiPairSwap: payments.push(last_payment); self.send().direct_multi(&caller, &payments); - self.emit_multi_pair_swap_event(caller, token_id, amount, payments.clone()); + self.emit_multi_pair_swap_event(&caller, &token_id, &amount, &payments); payments } diff --git a/dex/router/src/pair_actions/remove.rs b/dex/router/src/pair_actions/remove.rs index ecd58bd76..825daf1ad 100644 --- a/dex/router/src/pair_actions/remove.rs +++ b/dex/router/src/pair_actions/remove.rs @@ -27,6 +27,7 @@ pub trait RemoveModule: second_token_id.is_valid_esdt_identifier(), "Second Token ID is not a valid esdt token ID" ); + let mut pair_address = self.get_pair(first_token_id.clone(), second_token_id.clone()); require!(!pair_address.is_zero(), "Pair does not exists"); diff --git a/dex/router/src/pair_actions/tokens.rs b/dex/router/src/pair_actions/tokens.rs index 8e0f79c00..2658530a4 100644 --- a/dex/router/src/pair_actions/tokens.rs +++ b/dex/router/src/pair_actions/tokens.rs @@ -25,10 +25,7 @@ pub trait TokensModule: let issue_cost = self.call_value().egld_value().clone_value(); let caller = self.blockchain().get_caller(); if caller != self.owner().get() { - require!( - self.pair_creation_enabled().get(), - "Pair creation is disabled" - ); + self.require_pair_creation_enabled(); } self.check_is_pair_sc(&pair_address); @@ -105,6 +102,7 @@ pub trait TokensModule: match result { ManagedAsyncCallResult::Ok(()) => { self.pair_temporary_owner().remove(address); + let _: IgnoreValue = self .pair_contract_proxy_tokens(address.clone()) .set_lp_token_identifier(token_id.unwrap_esdt()) diff --git a/dex/router/src/pair_actions/upgrade.rs b/dex/router/src/pair_actions/upgrade.rs index 96ac67fa4..b68bf821f 100644 --- a/dex/router/src/pair_actions/upgrade.rs +++ b/dex/router/src/pair_actions/upgrade.rs @@ -27,6 +27,7 @@ pub trait UpgradeModule: second_token_id.is_valid_esdt_identifier(), "Second Token ID is not a valid esdt token ID" ); + let pair_address = self.get_pair(first_token_id.clone(), second_token_id.clone()); require!(!pair_address.is_zero(), "Pair does not exists"); diff --git a/dex/router/src/temp_owner.rs b/dex/router/src/temp_owner.rs index f8d9ca2b5..b283b7c66 100644 --- a/dex/router/src/temp_owner.rs +++ b/dex/router/src/temp_owner.rs @@ -12,11 +12,8 @@ pub trait TempOwnerModule { #[only_owner] #[endpoint(clearPairTemporaryOwnerStorage)] - fn clear_pair_temporary_owner_storage(&self) -> usize { - let size = self.pair_temporary_owner().len(); + fn clear_pair_temporary_owner_storage(&self) { self.pair_temporary_owner().clear(); - - size } fn get_pair_temporary_owner(&self, pair_address: &ManagedAddress) -> Option { @@ -24,7 +21,8 @@ pub trait TempOwnerModule { match result { Some((temporary_owner, creation_block)) => { let expire_block = creation_block + self.temporary_owner_period().get(); - if expire_block <= self.blockchain().get_block_nonce() { + let block_nonce = self.blockchain().get_block_nonce(); + if expire_block <= block_nonce { self.pair_temporary_owner().remove(pair_address); None diff --git a/dex/router/tests/router_setup/mod.rs b/dex/router/tests/router_setup/mod.rs index 02b372f71..3b7d246b1 100644 --- a/dex/router/tests/router_setup/mod.rs +++ b/dex/router/tests/router_setup/mod.rs @@ -6,13 +6,13 @@ use multiversx_sc_scenario::{ whitebox_legacy::*, DebugApi, }; -pub const PAIR_WASM_PATH: &str = "pair/output/pair.wasm"; -pub const ROUTER_WASM_PATH: &str = "router/output/router.wasm"; -pub const MEX_TOKEN_ID: &[u8] = b"MEX-abcdef"; -pub const WEGLD_TOKEN_ID: &[u8] = b"WEGLD-abcdef"; -pub const USDC_TOKEN_ID: &[u8] = b"USDC-abcdef"; -pub const LPMEX_TOKEN_ID: &[u8] = b"LPMEX-abcdef"; -pub const LPUSDC_TOKEN_ID: &[u8] = b"LPUSDC-abcdef"; +pub static PAIR_WASM_PATH: &str = "pair/output/pair.wasm"; +pub static ROUTER_WASM_PATH: &str = "router/output/router.wasm"; +pub static MEX_TOKEN_ID: &[u8] = b"MEX-abcdef"; +pub static WEGLD_TOKEN_ID: &[u8] = b"WEGLD-abcdef"; +pub static USDC_TOKEN_ID: &[u8] = b"USDC-abcdef"; +pub static LPMEX_TOKEN_ID: &[u8] = b"LPMEX-abcdef"; +pub static LPUSDC_TOKEN_ID: &[u8] = b"LPUSDC-abcdef"; pub const USER_TOTAL_MEX_TOKENS: u64 = 5_001_001_000; pub const USER_TOTAL_WEGLD_TOKENS: u64 = 5_002_002_000; @@ -36,13 +36,12 @@ use router::pair_actions::create::PairTokens; use router::pair_actions::multi_pair_swap::*; use router::*; -#[allow(dead_code)] pub struct RouterSetup where RouterObjBuilder: 'static + Copy + Fn() -> router::ContractObj, PairObjBuilder: 'static + Copy + Fn() -> pair::ContractObj, { - pub blockchain_wrapper: BlockchainStateWrapper, + pub b_mock: BlockchainStateWrapper, pub owner_address: Address, pub user_address: Address, pub router_wrapper: ContractObjWrapper, RouterObjBuilder>, @@ -57,87 +56,97 @@ where { pub fn new(router_builder: RouterObjBuilder, pair_builder: PairObjBuilder) -> Self { let rust_zero = rust_biguint!(0u64); - let mut blockchain_wrapper = BlockchainStateWrapper::new(); - let owner_addr = blockchain_wrapper.create_user_account(&rust_zero); + let mut b_mock = BlockchainStateWrapper::new(); + let owner_addr = b_mock.create_user_account(&rust_zero); - let router_wrapper = blockchain_wrapper.create_sc_account( + let router_wrapper = b_mock.create_sc_account( &rust_zero, Some(&owner_addr), router_builder, ROUTER_WASM_PATH, ); - let mex_pair_wrapper = blockchain_wrapper.create_sc_account( + let mex_pair_wrapper = b_mock.create_sc_account( &rust_zero, - Some(&owner_addr), + Some(router_wrapper.address_ref()), pair_builder, PAIR_WASM_PATH, ); - let usdc_pair_wrapper = blockchain_wrapper.create_sc_account( + let usdc_pair_wrapper = b_mock.create_sc_account( &rust_zero, - Some(&owner_addr), + Some(router_wrapper.address_ref()), pair_builder, PAIR_WASM_PATH, ); - blockchain_wrapper - .execute_tx(&owner_addr, &mex_pair_wrapper, &rust_zero, |sc| { - let first_token_id = managed_token_id!(WEGLD_TOKEN_ID); - let second_token_id = managed_token_id!(MEX_TOKEN_ID); - let router_address = managed_address!(&owner_addr); - let router_owner_address = managed_address!(&owner_addr); - let total_fee_percent = 300u64; - let special_fee_percent = 50u64; + b_mock + .execute_tx( + router_wrapper.address_ref(), + &mex_pair_wrapper, + &rust_zero, + |sc| { + let first_token_id = managed_token_id!(WEGLD_TOKEN_ID); + let second_token_id = managed_token_id!(MEX_TOKEN_ID); + let router_address = managed_address!(router_wrapper.address_ref()); + let router_owner_address = managed_address!(&owner_addr); + let total_fee_percent = 300u64; + let special_fee_percent = 50u64; - sc.init( - first_token_id, - second_token_id, - router_address, - router_owner_address, - total_fee_percent, - special_fee_percent, - ManagedAddress::::zero(), - MultiValueEncoded::>::new(), - ); + sc.init( + first_token_id, + second_token_id, + router_address, + router_owner_address, + total_fee_percent, + special_fee_percent, + ManagedAddress::::zero(), + MultiValueEncoded::>::new(), + ); - let lp_token_id = managed_token_id!(LPMEX_TOKEN_ID); - sc.lp_token_identifier().set(&lp_token_id); + let lp_token_id = managed_token_id!(LPMEX_TOKEN_ID); + sc.lp_token_identifier().set(&lp_token_id); - sc.state().set(State::Active); - }) + sc.state().set(State::Active); + }, + ) .assert_ok(); - blockchain_wrapper - .execute_tx(&owner_addr, &usdc_pair_wrapper, &rust_zero, |sc| { - let first_token_id = managed_token_id!(WEGLD_TOKEN_ID); - let second_token_id = managed_token_id!(USDC_TOKEN_ID); - let router_address = managed_address!(&owner_addr); - let router_owner_address = managed_address!(&owner_addr); - let total_fee_percent = 300u64; - let special_fee_percent = 50u64; + b_mock + .execute_tx( + router_wrapper.address_ref(), + &usdc_pair_wrapper, + &rust_zero, + |sc| { + let first_token_id = managed_token_id!(WEGLD_TOKEN_ID); + let second_token_id = managed_token_id!(USDC_TOKEN_ID); + let router_address = managed_address!(router_wrapper.address_ref()); + let router_owner_address = managed_address!(&owner_addr); + let total_fee_percent = 300u64; + let special_fee_percent = 50u64; - sc.init( - first_token_id, - second_token_id, - router_address, - router_owner_address, - total_fee_percent, - special_fee_percent, - ManagedAddress::::zero(), - MultiValueEncoded::>::new(), - ); + sc.init( + first_token_id, + second_token_id, + router_address, + router_owner_address, + total_fee_percent, + special_fee_percent, + ManagedAddress::::zero(), + MultiValueEncoded::>::new(), + ); - let lp_token_id = managed_token_id!(LPUSDC_TOKEN_ID); - sc.lp_token_identifier().set(&lp_token_id); + let lp_token_id = managed_token_id!(LPUSDC_TOKEN_ID); + sc.lp_token_identifier().set(&lp_token_id); - sc.state().set(State::Active); - }) + sc.state().set(State::Active); + }, + ) .assert_ok(); - blockchain_wrapper + b_mock .execute_tx(&owner_addr, &router_wrapper, &rust_zero, |sc| { - sc.init(OptionalValue::None); + sc.init(managed_token_id!(MEX_TOKEN_ID), OptionalValue::None); sc.pair_map().insert( PairTokens { @@ -157,38 +166,38 @@ where .assert_ok(); let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; - blockchain_wrapper.set_esdt_local_roles( + b_mock.set_esdt_local_roles( mex_pair_wrapper.address_ref(), LPMEX_TOKEN_ID, &lp_token_roles[..], ); let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; - blockchain_wrapper.set_esdt_local_roles( + b_mock.set_esdt_local_roles( usdc_pair_wrapper.address_ref(), LPUSDC_TOKEN_ID, &lp_token_roles[..], ); - let user_addr = blockchain_wrapper.create_user_account(&rust_biguint!(100_000_000)); - blockchain_wrapper.set_esdt_balance( + let user_addr = b_mock.create_user_account(&rust_biguint!(100_000_000)); + b_mock.set_esdt_balance( &user_addr, WEGLD_TOKEN_ID, &rust_biguint!(USER_TOTAL_WEGLD_TOKENS), ); - blockchain_wrapper.set_esdt_balance( + b_mock.set_esdt_balance( &user_addr, MEX_TOKEN_ID, &rust_biguint!(USER_TOTAL_MEX_TOKENS), ); - blockchain_wrapper.set_esdt_balance( + b_mock.set_esdt_balance( &user_addr, USDC_TOKEN_ID, &rust_biguint!(USER_TOTAL_USDC_TOKENS), ); RouterSetup { - blockchain_wrapper, + b_mock, owner_address: owner_addr, user_address: user_addr, router_wrapper, @@ -211,7 +220,7 @@ where }, ]; - self.blockchain_wrapper + self.b_mock .execute_esdt_multi_transfer( &self.user_address, &self.mex_pair_wrapper, @@ -238,7 +247,7 @@ where }, ]; - self.blockchain_wrapper + self.b_mock .execute_esdt_multi_transfer( &self.user_address, &self.usdc_pair_wrapper, @@ -261,7 +270,7 @@ where ) { let payment_amount_big = rust_biguint!(payment_amount); - self.blockchain_wrapper + self.b_mock .execute_esdt_transfer( &self.user_address, &self.router_wrapper, diff --git a/dex/router/tests/router_test.rs b/dex/router/tests/router_test.rs index 1008b007b..dc5876bad 100644 --- a/dex/router/tests/router_test.rs +++ b/dex/router/tests/router_test.rs @@ -1,6 +1,7 @@ #![allow(deprecated)] mod router_setup; +use common_structs::TokenPair; use multiversx_sc::{ codec::multi_types::OptionalValue, storage::mappers::StorageTokenWrapper, @@ -10,8 +11,8 @@ use multiversx_sc::{ }, }; use pair::{ - config::ConfigModule as PairConfigModule, pair_actions::initial_liq::InitialLiquidityModule, - Pair, + config::ConfigModule as PairConfigModule, fee::storage::StorageModule, + pair_actions::initial_liq::InitialLiquidityModule, Pair, }; use pausable::{PausableModule, State}; use router::{ @@ -94,10 +95,11 @@ fn test_router_upgrade_pair() { b_mock .execute_tx(&owner, &router_wrapper, &rust_zero, |sc| { - sc.init(OptionalValue::Some(managed_address!( - pair_template_wrapper.address_ref() - ))); - sc.set_pair_creation_enabled(true); + sc.init( + managed_token_id!(MEX_TOKEN_ID), + OptionalValue::Some(managed_address!(pair_template_wrapper.address_ref())), + ); + sc.set_pair_creation_enabled(); }) .assert_ok(); @@ -137,17 +139,17 @@ fn test_multi_pair_swap() { router_setup.add_liquidity(); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, WEGLD_TOKEN_ID, &rust_biguint!(5_000_000_000), ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, MEX_TOKEN_ID, &rust_biguint!(5_000_000_000), ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, USDC_TOKEN_ID, &rust_biguint!(5_000_000_000), @@ -170,17 +172,17 @@ fn test_multi_pair_swap() { router_setup.multi_pair_swap(MEX_TOKEN_ID, 100_000, &ops); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, WEGLD_TOKEN_ID, &rust_biguint!(5_000_000_000), //unchanged ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, MEX_TOKEN_ID, &rust_biguint!(4_999_900_000), //spent 100_000 ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, USDC_TOKEN_ID, &rust_biguint!(5_000_082_909), //gained 82_909 @@ -244,7 +246,7 @@ fn user_enable_pair_swaps_through_router_test() { // setup router b_mock .execute_tx(&owner, &router_wrapper, &rust_zero, |sc| { - sc.init(OptionalValue::None); + sc.init(managed_token_id!(MEX_TOKEN_ID), OptionalValue::None); sc.pair_map().insert( PairTokens { @@ -429,7 +431,7 @@ fn user_enable_pair_swaps_fail_test() { // setup router b_mock .execute_tx(&owner, &router_wrapper, &rust_zero, |sc| { - sc.init(OptionalValue::None); + sc.init(managed_token_id!(MEX_TOKEN_ID), OptionalValue::None); sc.pair_map().insert( PairTokens { @@ -564,3 +566,255 @@ fn user_enable_pair_swaps_fail_test() { }), ); } + +#[test] +fn user_enable_swaps_and_buyback_and_burn() { + let mut setup = RouterSetup::new(router::contract_obj, pair::contract_obj); + + let current_epoch = 5; + setup.b_mock.set_block_epoch(current_epoch); + + setup.b_mock.set_esdt_balance( + &setup.user_address, + CUSTOM_TOKEN_ID, + &rust_biguint!(USER_CUSTOM_TOKEN_BALANCE), + ); + setup.b_mock.set_esdt_balance( + &setup.user_address, + WEGLD_TOKEN_ID, + &rust_biguint!(USER_USDC_BALANCE), + ); + + let new_pair_wrapper = setup.b_mock.create_sc_account( + &rust_biguint!(0), + Some(setup.router_wrapper.address_ref()), + pair::contract_obj, + PAIR_WASM_PATH, + ); + let simple_lock_wrapper = setup.b_mock.create_sc_account( + &rust_biguint!(0), + Some(&setup.owner_address), + simple_lock::contract_obj, + "simple-lock.wasm", + ); + + // setup simple-lock + setup + .b_mock + .execute_tx( + &setup.owner_address, + &simple_lock_wrapper, + &rust_biguint!(0), + |sc| { + sc.locked_token() + .set_token_id(managed_token_id!(LOCKED_TOKEN_ID)); + }, + ) + .assert_ok(); + + setup.b_mock.set_esdt_local_roles( + simple_lock_wrapper.address_ref(), + LOCKED_TOKEN_ID, + &[ + EsdtLocalRole::NftCreate, + EsdtLocalRole::NftAddQuantity, + EsdtLocalRole::NftBurn, + ], + ); + + // setup router + setup + .b_mock + .execute_tx( + &setup.owner_address, + &setup.router_wrapper, + &rust_biguint!(0), + |sc| { + sc.pair_map().insert( + PairTokens { + first_token_id: managed_token_id!(CUSTOM_TOKEN_ID), + second_token_id: managed_token_id!(WEGLD_TOKEN_ID), + }, + managed_address!(new_pair_wrapper.address_ref()), + ); + + sc.add_common_tokens_for_user_pairs(MultiValueEncoded::from(ManagedVec::from( + vec![managed_token_id!(WEGLD_TOKEN_ID)], + ))); + + sc.config_enable_by_user_parameters( + managed_token_id!(WEGLD_TOKEN_ID), + managed_token_id!(LOCKED_TOKEN_ID), + managed_biguint!(MIN_LOCKED_TOKEN_VALUE), + MIN_LOCKED_PERIOD_EPOCHS, + ) + }, + ) + .assert_ok(); + + // setup pair + let router_address = setup.router_wrapper.address_ref().clone(); + let owner_address = setup.owner_address.clone(); + let user_address = setup.user_address.clone(); + setup + .b_mock + .execute_tx( + setup.router_wrapper.address_ref(), + &new_pair_wrapper, + &rust_biguint!(0), + |sc| { + let first_token_id = managed_token_id!(CUSTOM_TOKEN_ID); + let second_token_id = managed_token_id!(WEGLD_TOKEN_ID); + let router_address = managed_address!(&router_address); + let router_owner_address = managed_address!(&owner_address); + + sc.init( + first_token_id, + second_token_id, + router_address, + router_owner_address, + 0, + 0, + managed_address!(&user_address), + MultiValueEncoded::>::new(), + ); + + assert_eq!(sc.state().get(), State::Inactive); + + sc.lp_token_identifier() + .set(&managed_token_id!(LPUSDC_TOKEN_ID)); + }, + ) + .assert_ok(); + + setup.b_mock.set_esdt_local_roles( + new_pair_wrapper.address_ref(), + LPUSDC_TOKEN_ID, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + // add liquidity + let payments = vec![ + TxTokenTransfer { + token_identifier: CUSTOM_TOKEN_ID.to_vec(), + nonce: 0, + value: rust_biguint!(USER_CUSTOM_TOKEN_BALANCE), + }, + TxTokenTransfer { + token_identifier: WEGLD_TOKEN_ID.to_vec(), + nonce: 0, + value: rust_biguint!(USER_USDC_BALANCE), + }, + ]; + + let user_lp_tokens_balance = 999_000u64; + setup + .b_mock + .execute_esdt_multi_transfer(&setup.user_address, &new_pair_wrapper, &payments, |sc| { + let (lp_tokens_received, _, _) = sc.add_initial_liquidity().into_tuple(); + assert_eq!( + lp_tokens_received.token_identifier, + managed_token_id!(LPUSDC_TOKEN_ID) + ); + assert_eq!( + lp_tokens_received.amount, + managed_biguint!(user_lp_tokens_balance) + ); + }) + .assert_ok(); + + // lock LP tokens + setup + .b_mock + .execute_esdt_transfer( + &setup.user_address, + &simple_lock_wrapper, + LPUSDC_TOKEN_ID, + 0, + &rust_biguint!(user_lp_tokens_balance), + |sc| { + sc.lock_tokens_endpoint( + current_epoch + MIN_LOCKED_PERIOD_EPOCHS, + OptionalValue::None, + ); + }, + ) + .assert_ok(); + + DebugApi::dummy(); + setup.b_mock.check_nft_balance( + &setup.user_address, + LOCKED_TOKEN_ID, + 1, + &rust_biguint!(user_lp_tokens_balance), + Some(&LockedTokenAttributes:: { + original_token_id: managed_token_id_wrapped!(LPUSDC_TOKEN_ID), + original_token_nonce: 0, + unlock_epoch: current_epoch + MIN_LOCKED_PERIOD_EPOCHS, + }), + ); + + // pass blocks time to update safe price + setup.b_mock.set_block_nonce(1_000_000); + + // activate swaps through router + setup + .b_mock + .execute_esdt_transfer( + &setup.user_address, + &setup.router_wrapper, + LOCKED_TOKEN_ID, + 1, + &rust_biguint!(user_lp_tokens_balance), + |sc| { + sc.set_swap_enabled_by_user(managed_address!(new_pair_wrapper.address_ref())); + }, + ) + .assert_ok(); + + // check pair state is active + setup + .b_mock + .execute_query(&new_pair_wrapper, |sc| { + assert_eq!(sc.state().get(), State::Active); + }) + .assert_ok(); + + // check user received the locked tokens back + setup.b_mock.check_nft_balance( + &setup.user_address, + LOCKED_TOKEN_ID, + 1, + &rust_biguint!(user_lp_tokens_balance), + Some(&LockedTokenAttributes:: { + original_token_id: managed_token_id_wrapped!(LPUSDC_TOKEN_ID), + original_token_nonce: 0, + unlock_epoch: current_epoch + MIN_LOCKED_PERIOD_EPOCHS, + }), + ); + + // check new pair was whitelisted in existing pair + setup + .b_mock + .execute_query(&setup.mex_pair_wrapper, |sc| { + assert!(sc + .whitelist() + .contains(&managed_address!(new_pair_wrapper.address_ref()))); + }) + .assert_ok(); + + setup + .b_mock + .execute_query(&new_pair_wrapper, |sc| { + // check existing pair was added as trusted swap in new pair + assert!(sc.trusted_swap_pair().contains_key(&TokenPair { + first_token: managed_token_id!(WEGLD_TOKEN_ID), + second_token: managed_token_id!(MEX_TOKEN_ID), + })); + + // check fee was set on + let opt_entry = sc.destination_map().get(&ManagedAddress::zero()); + assert_eq!(opt_entry, Some(managed_token_id!(MEX_TOKEN_ID))); + }) + .assert_ok(); +} diff --git a/dex/router/wasm/src/lib.rs b/dex/router/wasm/src/lib.rs index 9f5f7ed7f..2592ff2c4 100644 --- a/dex/router/wasm/src/lib.rs +++ b/dex/router/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 29 +// Endpoints: 31 // Async Callback: 1 -// Total number of exported functions: 32 +// Total number of exported functions: 34 #![no_std] @@ -22,6 +22,7 @@ multiversx_sc_wasm_adapter::endpoints! { upgrade => upgrade setPairTemplateAddress => set_pair_template_address setPairCreationEnabled => set_pair_creation_enabled + setPairCreationDisabled => set_pair_creation_disabled getPairCreationEnabled => pair_creation_enabled getOwner => owner getPairTemplateAddress => pair_template_address @@ -31,6 +32,7 @@ multiversx_sc_wasm_adapter::endpoints! { removeCommonTokensForUserPairs => remove_common_tokens_for_user_pairs setSwapEnabledByUser => set_swap_enabled_by_user getEnableSwapByUserConfig => try_get_config + setTokenToBuy => set_token_to_buy multiPairSwap => multi_pair_swap createPair => create_pair_endpoint upgradePair => upgrade_pair_endpoint diff --git a/dex/tests/dex_scenario_go_test.rs b/dex/tests/dex_scenario_go_test.rs index 5675b0a8d..a412724a6 100644 --- a/dex/tests/dex_scenario_go_test.rs +++ b/dex/tests/dex_scenario_go_test.rs @@ -1,205 +1,205 @@ -use multiversx_sc_scenario::*; - -fn world() -> ScenarioWorld { - ScenarioWorld::vm_go() -} - -#[test] -fn add_liquidity_go() { - world().run("scenarios/add_liquidity.scen.json"); -} - -#[test] -fn calculate_rewards_for_given_position_go() { - world().run("scenarios/calculate_rewards_for_given_position.scen.json"); -} - -#[test] -fn calculate_rewards_for_given_position_after_compound_go() { - world().run("scenarios/calculate_rewards_for_given_position_after_compound.scen.json"); -} - -#[test] -fn check_fee_disabled_after_swap_go() { - world().run("scenarios/check_fee_disabled_after_swap.scen.json"); -} - -#[test] -fn check_fee_enabled_after_swap_go() { - world().run("scenarios/check_fee_enabled_after_swap.scen.json"); -} - -#[test] -fn claim_rewards_go() { - world().run("scenarios/claim_rewards.scen.json"); -} - -#[test] -fn complete_setup_go() { - world().run("scenarios/complete_setup.scen.json"); -} - -#[test] -fn compound_rewards_go() { - world().run("scenarios/compound_rewards.scen.json"); -} - -#[test] -fn create_pair_twice_go() { - world().run("scenarios/create_pair_twice.scen.json"); -} - -#[test] -fn enter_farm_go() { - world().run("scenarios/enter_farm.scen.json"); -} - -#[test] -fn enter_farm_with_merge_tokens_go() { - world().run("scenarios/enter_farm_with_merge_tokens.scen.json"); -} - -#[test] -fn enter_mex_farm_go() { - world().run("scenarios/enter_mex_farm.scen.json"); -} - -#[test] -fn exit_farm_go() { - world().run("scenarios/exit_farm.scen.json"); -} - -#[test] -fn exit_farm_too_soon_go() { - world().run("scenarios/exit_farm_too_soon.scen.json"); -} - -#[test] -fn exit_mex_farm_go() { - world().run("scenarios/exit_mex_farm.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_1_go() { - world().run("scenarios/farm_reward_distr_scen_1.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_2_go() { - world().run("scenarios/farm_reward_distr_scen_2.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_3_go() { - world().run("scenarios/farm_reward_distr_scen_3.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_4_go() { - world().run("scenarios/farm_reward_distr_scen_4.scen.json"); -} - -#[test] -fn farm_with_egld_token_go() { - world().run("scenarios/farm_with_egld_token.scen.json"); -} - -#[test] -fn farm_wrong_lp_token_go() { - world().run("scenarios/farm_wrong_lp_token.scen.json"); -} - -#[test] -fn get_amounts_go() { - world().run("scenarios/get_amounts.scen.json"); -} - -#[test] -fn get_amounts_no_liquidity_go() { - world().run("scenarios/get_amounts_no_liquidity.scen.json"); -} - -#[test] -fn get_pair_non_existent_go() { - world().run("scenarios/get_pair_non_existent.scen.json"); -} - -#[test] -fn get_pair_views_go() { - world().run("scenarios/get_pair_views.scen.json"); -} - -#[test] -fn merge_tokens_go() { - world().run("scenarios/merge_tokens.scen.json"); -} - -#[test] -fn owner_pause_farm_go() { - world().run("scenarios/owner_pause_farm.scen.json"); -} - -#[test] -fn owner_resume_farm_go() { - world().run("scenarios/owner_resume_farm.scen.json"); -} - -#[test] -fn remove_liquidity_go() { - world().run("scenarios/remove_liquidity.scen.json"); -} - -#[test] -fn remove_liquidity_and_buyback_and_burn_token_go() { - world().run("scenarios/remove_liquidity_and_buyback_and_burn_token.scen.json"); -} - -#[test] -fn remove_liquidity_twice_go() { - world().run("scenarios/remove_liquidity_twice.scen.json"); -} - -#[test] -fn remove_pair_go() { - world().run("scenarios/remove_pair.scen.json"); -} - -#[test] -fn router_pause_self_go() { - world().run("scenarios/router_pause_self.scen.json"); -} - -#[test] -fn router_resume_self_go() { - world().run("scenarios/router_resume_self.scen.json"); -} - -#[test] -fn swap_fixed_input_go() { - world().run("scenarios/swap_fixed_input.scen.json"); -} - -#[test] -fn swap_fixed_input_after_removed_liquidity_go() { - world().run("scenarios/swap_fixed_input_after_removed_liquidity.scen.json"); -} - -#[test] -fn swap_fixed_output_go() { - world().run("scenarios/swap_fixed_output.scen.json"); -} - -#[test] -fn swap_same_token_go() { - world().run("scenarios/swap_same_token.scen.json"); -} - -#[test] -fn swap_wrong_token_go() { - world().run("scenarios/swap_wrong_token.scen.json"); -} - -#[test] -fn upgrade_contract_go() { - world().run("scenarios/upgrade_contract.scen.json"); -} +// use multiversx_sc_scenario::*; + +// fn world() -> ScenarioWorld { +// ScenarioWorld::vm_go() +// } + +// #[test] +// fn add_liquidity_go() { +// world().run("scenarios/add_liquidity.scen.json"); +// } + +// #[test] +// fn calculate_rewards_for_given_position_go() { +// world().run("scenarios/calculate_rewards_for_given_position.scen.json"); +// } + +// #[test] +// fn calculate_rewards_for_given_position_after_compound_go() { +// world().run("scenarios/calculate_rewards_for_given_position_after_compound.scen.json"); +// } + +// #[test] +// fn check_fee_disabled_after_swap_go() { +// world().run("scenarios/check_fee_disabled_after_swap.scen.json"); +// } + +// #[test] +// fn check_fee_enabled_after_swap_go() { +// world().run("scenarios/check_fee_enabled_after_swap.scen.json"); +// } + +// #[test] +// fn claim_rewards_go() { +// world().run("scenarios/claim_rewards.scen.json"); +// } + +// #[test] +// fn complete_setup_go() { +// world().run("scenarios/complete_setup.scen.json"); +// } + +// #[test] +// fn compound_rewards_go() { +// world().run("scenarios/compound_rewards.scen.json"); +// } + +// #[test] +// fn create_pair_twice_go() { +// world().run("scenarios/create_pair_twice.scen.json"); +// } + +// #[test] +// fn enter_farm_go() { +// world().run("scenarios/enter_farm.scen.json"); +// } + +// #[test] +// fn enter_farm_with_merge_tokens_go() { +// world().run("scenarios/enter_farm_with_merge_tokens.scen.json"); +// } + +// #[test] +// fn enter_mex_farm_go() { +// world().run("scenarios/enter_mex_farm.scen.json"); +// } + +// #[test] +// fn exit_farm_go() { +// world().run("scenarios/exit_farm.scen.json"); +// } + +// #[test] +// fn exit_farm_too_soon_go() { +// world().run("scenarios/exit_farm_too_soon.scen.json"); +// } + +// #[test] +// fn exit_mex_farm_go() { +// world().run("scenarios/exit_mex_farm.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_1_go() { +// world().run("scenarios/farm_reward_distr_scen_1.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_2_go() { +// world().run("scenarios/farm_reward_distr_scen_2.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_3_go() { +// world().run("scenarios/farm_reward_distr_scen_3.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_4_go() { +// world().run("scenarios/farm_reward_distr_scen_4.scen.json"); +// } + +// #[test] +// fn farm_with_egld_token_go() { +// world().run("scenarios/farm_with_egld_token.scen.json"); +// } + +// #[test] +// fn farm_wrong_lp_token_go() { +// world().run("scenarios/farm_wrong_lp_token.scen.json"); +// } + +// #[test] +// fn get_amounts_go() { +// world().run("scenarios/get_amounts.scen.json"); +// } + +// #[test] +// fn get_amounts_no_liquidity_go() { +// world().run("scenarios/get_amounts_no_liquidity.scen.json"); +// } + +// #[test] +// fn get_pair_non_existent_go() { +// world().run("scenarios/get_pair_non_existent.scen.json"); +// } + +// #[test] +// fn get_pair_views_go() { +// world().run("scenarios/get_pair_views.scen.json"); +// } + +// #[test] +// fn merge_tokens_go() { +// world().run("scenarios/merge_tokens.scen.json"); +// } + +// #[test] +// fn owner_pause_farm_go() { +// world().run("scenarios/owner_pause_farm.scen.json"); +// } + +// #[test] +// fn owner_resume_farm_go() { +// world().run("scenarios/owner_resume_farm.scen.json"); +// } + +// #[test] +// fn remove_liquidity_go() { +// world().run("scenarios/remove_liquidity.scen.json"); +// } + +// #[test] +// fn remove_liquidity_and_buyback_and_burn_token_go() { +// world().run("scenarios/remove_liquidity_and_buyback_and_burn_token.scen.json"); +// } + +// #[test] +// fn remove_liquidity_twice_go() { +// world().run("scenarios/remove_liquidity_twice.scen.json"); +// } + +// #[test] +// fn remove_pair_go() { +// world().run("scenarios/remove_pair.scen.json"); +// } + +// #[test] +// fn router_pause_self_go() { +// world().run("scenarios/router_pause_self.scen.json"); +// } + +// #[test] +// fn router_resume_self_go() { +// world().run("scenarios/router_resume_self.scen.json"); +// } + +// #[test] +// fn swap_fixed_input_go() { +// world().run("scenarios/swap_fixed_input.scen.json"); +// } + +// #[test] +// fn swap_fixed_input_after_removed_liquidity_go() { +// world().run("scenarios/swap_fixed_input_after_removed_liquidity.scen.json"); +// } + +// #[test] +// fn swap_fixed_output_go() { +// world().run("scenarios/swap_fixed_output.scen.json"); +// } + +// #[test] +// fn swap_same_token_go() { +// world().run("scenarios/swap_same_token.scen.json"); +// } + +// #[test] +// fn swap_wrong_token_go() { +// world().run("scenarios/swap_wrong_token.scen.json"); +// } + +// #[test] +// fn upgrade_contract_go() { +// world().run("scenarios/upgrade_contract.scen.json"); +// } diff --git a/dex/tests/dex_scenario_rs_test.rs b/dex/tests/dex_scenario_rs_test.rs index 3a0b16a81..1cb502b6f 100644 --- a/dex/tests/dex_scenario_rs_test.rs +++ b/dex/tests/dex_scenario_rs_test.rs @@ -1,211 +1,211 @@ -use multiversx_sc_scenario::ScenarioWorld; - -fn world() -> ScenarioWorld { - let mut blockchain = ScenarioWorld::new(); - - blockchain.register_contract("file:router/output/router.wasm", router::ContractBuilder); - blockchain.register_contract("file:pair/output/pair.wasm", pair::ContractBuilder); - blockchain.register_contract("file:farm/output/farm.wasm", farm::ContractBuilder); - - blockchain -} - -#[test] -fn add_liquidity_rs() { - world().run("scenarios/add_liquidity.scen.json"); -} - -#[test] -fn calculate_rewards_for_given_position_rs() { - world().run("scenarios/calculate_rewards_for_given_position.scen.json"); -} - -#[test] -fn calculate_rewards_for_given_position_after_compound_rs() { - world().run("scenarios/calculate_rewards_for_given_position_after_compound.scen.json"); -} - -#[test] -fn check_fee_disabled_after_swap_rs() { - world().run("scenarios/check_fee_disabled_after_swap.scen.json"); -} - -#[test] -fn check_fee_enabled_after_swap_rs() { - world().run("scenarios/check_fee_enabled_after_swap.scen.json"); -} - -#[test] -fn claim_rewards_rs() { - world().run("scenarios/claim_rewards.scen.json"); -} - -#[test] -fn complete_setup_rs() { - world().run("scenarios/complete_setup.scen.json"); -} - -#[test] -fn compound_rewards_rs() { - world().run("scenarios/compound_rewards.scen.json"); -} - -#[test] -fn create_pair_twice_rs() { - world().run("scenarios/create_pair_twice.scen.json"); -} - -#[test] -fn enter_farm_rs() { - world().run("scenarios/enter_farm.scen.json"); -} - -#[test] -fn enter_farm_with_merge_tokens_rs() { - world().run("scenarios/enter_farm_with_merge_tokens.scen.json"); -} - -#[test] -fn enter_mex_farm_rs() { - world().run("scenarios/enter_mex_farm.scen.json"); -} - -#[test] -fn exit_farm_rs() { - world().run("scenarios/exit_farm.scen.json"); -} - -#[test] -fn exit_farm_too_soon_rs() { - world().run("scenarios/exit_farm_too_soon.scen.json"); -} - -#[test] -fn exit_mex_farm_rs() { - world().run("scenarios/exit_mex_farm.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_1_rs() { - world().run("scenarios/farm_reward_distr_scen_1.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_2_rs() { - world().run("scenarios/farm_reward_distr_scen_2.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_3_rs() { - world().run("scenarios/farm_reward_distr_scen_3.scen.json"); -} - -#[test] -fn farm_reward_distr_scen_4_rs() { - world().run("scenarios/farm_reward_distr_scen_4.scen.json"); -} - -#[test] -fn farm_with_egld_token_rs() { - world().run("scenarios/farm_with_egld_token.scen.json"); -} - -#[test] -fn farm_wrong_lp_token_rs() { - world().run("scenarios/farm_wrong_lp_token.scen.json"); -} - -#[test] -fn get_amounts_rs() { - world().run("scenarios/get_amounts.scen.json"); -} - -#[test] -fn get_amounts_no_liquidity_rs() { - world().run("scenarios/get_amounts_no_liquidity.scen.json"); -} - -#[test] -fn get_pair_non_existent_rs() { - world().run("scenarios/get_pair_non_existent.scen.json"); -} - -#[test] -fn get_pair_views_rs() { - world().run("scenarios/get_pair_views.scen.json"); -} - -#[test] -fn merge_tokens_rs() { - world().run("scenarios/merge_tokens.scen.json"); -} - -#[test] -fn owner_pause_farm_rs() { - world().run("scenarios/owner_pause_farm.scen.json"); -} - -#[test] -fn owner_resume_farm_rs() { - world().run("scenarios/owner_resume_farm.scen.json"); -} - -#[test] -fn remove_liquidity_rs() { - world().run("scenarios/remove_liquidity.scen.json"); -} - -#[test] -fn remove_liquidity_and_buyback_and_burn_token_rs() { - world().run("scenarios/remove_liquidity_and_buyback_and_burn_token.scen.json"); -} - -#[test] -fn remove_liquidity_twice_rs() { - world().run("scenarios/remove_liquidity_twice.scen.json"); -} - -#[test] -fn remove_pair_rs() { - world().run("scenarios/remove_pair.scen.json"); -} - -#[test] -fn router_pause_self_rs() { - world().run("scenarios/router_pause_self.scen.json"); -} - -#[test] -fn router_resume_self_rs() { - world().run("scenarios/router_resume_self.scen.json"); -} - -#[test] -fn swap_fixed_input_rs() { - world().run("scenarios/swap_fixed_input.scen.json"); -} - -#[test] -fn swap_fixed_input_after_removed_liquidity_rs() { - world().run("scenarios/swap_fixed_input_after_removed_liquidity.scen.json"); -} - -#[test] -fn swap_fixed_output_rs() { - world().run("scenarios/swap_fixed_output.scen.json"); -} - -#[test] -fn swap_same_token_rs() { - world().run("scenarios/swap_same_token.scen.json"); -} - -#[test] -fn swap_wrong_token_rs() { - world().run("scenarios/swap_wrong_token.scen.json"); -} - -#[test] -fn upgrade_contract_rs() { - world().run("scenarios/upgrade_contract.scen.json"); -} +// use multiversx_sc_scenario::ScenarioWorld; + +// fn world() -> ScenarioWorld { +// let mut blockchain = ScenarioWorld::new(); + +// blockchain.register_contract("file:router/output/router.wasm", router::ContractBuilder); +// blockchain.register_contract("file:pair/output/pair.wasm", pair::ContractBuilder); +// blockchain.register_contract("file:farm/output/farm.wasm", farm::ContractBuilder); + +// blockchain +// } + +// #[test] +// fn add_liquidity_rs() { +// world().run("scenarios/add_liquidity.scen.json"); +// } + +// #[test] +// fn calculate_rewards_for_given_position_rs() { +// world().run("scenarios/calculate_rewards_for_given_position.scen.json"); +// } + +// #[test] +// fn calculate_rewards_for_given_position_after_compound_rs() { +// world().run("scenarios/calculate_rewards_for_given_position_after_compound.scen.json"); +// } + +// #[test] +// fn check_fee_disabled_after_swap_rs() { +// world().run("scenarios/check_fee_disabled_after_swap.scen.json"); +// } + +// #[test] +// fn check_fee_enabled_after_swap_rs() { +// world().run("scenarios/check_fee_enabled_after_swap.scen.json"); +// } + +// #[test] +// fn claim_rewards_rs() { +// world().run("scenarios/claim_rewards.scen.json"); +// } + +// #[test] +// fn complete_setup_rs() { +// world().run("scenarios/complete_setup.scen.json"); +// } + +// #[test] +// fn compound_rewards_rs() { +// world().run("scenarios/compound_rewards.scen.json"); +// } + +// #[test] +// fn create_pair_twice_rs() { +// world().run("scenarios/create_pair_twice.scen.json"); +// } + +// #[test] +// fn enter_farm_rs() { +// world().run("scenarios/enter_farm.scen.json"); +// } + +// #[test] +// fn enter_farm_with_merge_tokens_rs() { +// world().run("scenarios/enter_farm_with_merge_tokens.scen.json"); +// } + +// #[test] +// fn enter_mex_farm_rs() { +// world().run("scenarios/enter_mex_farm.scen.json"); +// } + +// #[test] +// fn exit_farm_rs() { +// world().run("scenarios/exit_farm.scen.json"); +// } + +// #[test] +// fn exit_farm_too_soon_rs() { +// world().run("scenarios/exit_farm_too_soon.scen.json"); +// } + +// #[test] +// fn exit_mex_farm_rs() { +// world().run("scenarios/exit_mex_farm.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_1_rs() { +// world().run("scenarios/farm_reward_distr_scen_1.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_2_rs() { +// world().run("scenarios/farm_reward_distr_scen_2.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_3_rs() { +// world().run("scenarios/farm_reward_distr_scen_3.scen.json"); +// } + +// #[test] +// fn farm_reward_distr_scen_4_rs() { +// world().run("scenarios/farm_reward_distr_scen_4.scen.json"); +// } + +// #[test] +// fn farm_with_egld_token_rs() { +// world().run("scenarios/farm_with_egld_token.scen.json"); +// } + +// #[test] +// fn farm_wrong_lp_token_rs() { +// world().run("scenarios/farm_wrong_lp_token.scen.json"); +// } + +// #[test] +// fn get_amounts_rs() { +// world().run("scenarios/get_amounts.scen.json"); +// } + +// #[test] +// fn get_amounts_no_liquidity_rs() { +// world().run("scenarios/get_amounts_no_liquidity.scen.json"); +// } + +// #[test] +// fn get_pair_non_existent_rs() { +// world().run("scenarios/get_pair_non_existent.scen.json"); +// } + +// #[test] +// fn get_pair_views_rs() { +// world().run("scenarios/get_pair_views.scen.json"); +// } + +// #[test] +// fn merge_tokens_rs() { +// world().run("scenarios/merge_tokens.scen.json"); +// } + +// #[test] +// fn owner_pause_farm_rs() { +// world().run("scenarios/owner_pause_farm.scen.json"); +// } + +// #[test] +// fn owner_resume_farm_rs() { +// world().run("scenarios/owner_resume_farm.scen.json"); +// } + +// #[test] +// fn remove_liquidity_rs() { +// world().run("scenarios/remove_liquidity.scen.json"); +// } + +// #[test] +// fn remove_liquidity_and_buyback_and_burn_token_rs() { +// world().run("scenarios/remove_liquidity_and_buyback_and_burn_token.scen.json"); +// } + +// #[test] +// fn remove_liquidity_twice_rs() { +// world().run("scenarios/remove_liquidity_twice.scen.json"); +// } + +// #[test] +// fn remove_pair_rs() { +// world().run("scenarios/remove_pair.scen.json"); +// } + +// #[test] +// fn router_pause_self_rs() { +// world().run("scenarios/router_pause_self.scen.json"); +// } + +// #[test] +// fn router_resume_self_rs() { +// world().run("scenarios/router_resume_self.scen.json"); +// } + +// #[test] +// fn swap_fixed_input_rs() { +// world().run("scenarios/swap_fixed_input.scen.json"); +// } + +// #[test] +// fn swap_fixed_input_after_removed_liquidity_rs() { +// world().run("scenarios/swap_fixed_input_after_removed_liquidity.scen.json"); +// } + +// #[test] +// fn swap_fixed_output_rs() { +// world().run("scenarios/swap_fixed_output.scen.json"); +// } + +// #[test] +// fn swap_same_token_rs() { +// world().run("scenarios/swap_same_token.scen.json"); +// } + +// #[test] +// fn swap_wrong_token_rs() { +// world().run("scenarios/swap_wrong_token.scen.json"); +// } + +// #[test] +// fn upgrade_contract_rs() { +// world().run("scenarios/upgrade_contract.scen.json"); +// } 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/locked-asset/lkmex-transfer/src/lib.rs b/locked-asset/lkmex-transfer/src/lib.rs index 126e740b8..a166c08de 100644 --- a/locked-asset/lkmex-transfer/src/lib.rs +++ b/locked-asset/lkmex-transfer/src/lib.rs @@ -53,7 +53,7 @@ pub trait LkmexTransfer: self.set_energy_factory_address(energy_factory_address); let caller = self.blockchain().get_caller(); - self.add_permissions(caller, Permissions::OWNER); + self.add_permissions(&caller, Permissions::OWNER); } #[upgrade]