From 8fd716c74aa9e43c49d0a481309bd87a2339dfbe Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Tue, 26 Nov 2024 14:27:39 +0200 Subject: [PATCH] impl --- dex/proxy-deployer/src/deploy.rs | 134 ++++++++++++++++++++++++++ dex/proxy-deployer/src/farm_deploy.rs | 87 ----------------- dex/proxy-deployer/src/lib.rs | 25 ++++- dex/proxy-deployer/src/storage.rs | 25 +++++ dex/proxy-deployer/src/views.rs | 81 ++++++++++++++++ dex/proxy-deployer/wasm/src/lib.rs | 14 +-- 6 files changed, 268 insertions(+), 98 deletions(-) create mode 100644 dex/proxy-deployer/src/deploy.rs delete mode 100644 dex/proxy-deployer/src/farm_deploy.rs create mode 100644 dex/proxy-deployer/src/storage.rs create mode 100644 dex/proxy-deployer/src/views.rs diff --git a/dex/proxy-deployer/src/deploy.rs b/dex/proxy-deployer/src/deploy.rs new file mode 100644 index 000000000..e88d347e1 --- /dev/null +++ b/dex/proxy-deployer/src/deploy.rs @@ -0,0 +1,134 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem)] +pub struct ForcedDeployArg { + pub arg_nr: usize, + pub value: ManagedBuffer, +} + +pub type ForcedDeployArgsType = MultiValueEncoded>>; + +#[multiversx_sc::module] +pub trait DeployModule: crate::storage::StorageModule { + /// Forced deploy args contain the index of the arg, and the argument itself. + /// + /// They must be provided in the order expected by the deployed SCs arguments order. + #[only_owner] + #[endpoint(overwriteForcedDeployArgs)] + fn overwrite_forced_deploy_args(&self, forced_deploy_args: ForcedDeployArgsType) { + let mut forced_args = ManagedVec::new(); + for forced_arg_multi in forced_deploy_args { + let (index, arg) = forced_arg_multi.into_tuple(); + let forced_arg = ForcedDeployArg { + arg_nr: index, + value: arg, + }; + forced_args.push(forced_arg); + } + + self.forced_deploy_args().set(forced_args); + } + + #[endpoint(deployContract)] + fn deploy_contract( + &self, + token_used_by_sc: TokenIdentifier, + args: MultiValueEncoded, + ) -> ManagedAddress { + require!( + !self.all_used_tokens().contains(&token_used_by_sc), + "Token already used" + ); + + let arg_buffer = self.prepare_deploy_args(args.into_vec_of_buffers()); + let deployed_sc_address = self.deploy_from_source(&arg_buffer); + + let address_id = self.address_id().insert_new(&deployed_sc_address); + let _ = self.all_deployed_contracts().insert(address_id); + self.address_for_token(&token_used_by_sc).set(address_id); + + let _ = self.all_used_tokens().insert(token_used_by_sc); + + deployed_sc_address + } + + fn prepare_deploy_args( + &self, + provided_args: ManagedVec, + ) -> ManagedArgBuffer { + let mut arg_buffer = ManagedArgBuffer::new(); + + let mut forced_args = self.forced_deploy_args().get(); + let mut opt_current_forced_arg = self.get_next_forced_arg(&mut forced_args); + + let mut all_args_index = 0; + let mut provided_args_index = 0; + let provided_args_len = provided_args.len(); + while provided_args_index < provided_args_len { + if let Some(current_forced_arg) = &opt_current_forced_arg { + if current_forced_arg.arg_nr == all_args_index { + arg_buffer.push_arg_raw(current_forced_arg.value.clone()); + opt_current_forced_arg = self.get_next_forced_arg(&mut forced_args); + + all_args_index += 1; + + continue; + } + } + + let provided_arg = provided_args.get(provided_args_index); + arg_buffer.push_arg_raw((*provided_arg).clone()); + + provided_args_index += 1; + all_args_index += 1; + } + + while let Some(current_forced_arg) = &opt_current_forced_arg { + if current_forced_arg.arg_nr == all_args_index { + arg_buffer.push_arg_raw(current_forced_arg.value.clone()); + opt_current_forced_arg = self.get_next_forced_arg(&mut forced_args); + + all_args_index += 1; + } else { + break; + } + } + + // All contracts have the admins list as last argument + let caller = self.blockchain().get_caller(); + arg_buffer.push_arg_raw(caller.as_managed_buffer().clone()); + + arg_buffer + } + + fn get_next_forced_arg( + &self, + forced_args: &mut ManagedVec>, + ) -> Option> { + if forced_args.is_empty() { + return None; + } + + let arg = forced_args.get(0); + forced_args.remove(0); + + Some(arg) + } + + fn deploy_from_source(&self, args: &ManagedArgBuffer) -> ManagedAddress { + let template = self.template_address().get(); + let code_metadata = + CodeMetadata::PAYABLE_BY_SC | CodeMetadata::READABLE | CodeMetadata::UPGRADEABLE; + let gas_left = self.blockchain().get_gas_left(); + let (deployed_sc_address, _) = self.send_raw().deploy_from_source_contract( + gas_left, + &BigUint::zero(), + &template, + code_metadata, + args, + ); + + deployed_sc_address + } +} 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..0e80e074c 100644 --- a/dex/proxy-deployer/src/lib.rs +++ b/dex/proxy-deployer/src/lib.rs @@ -1,19 +1,34 @@ #![no_std] +use deploy::ForcedDeployArgsType; + multiversx_sc::imports!(); -pub mod farm_deploy; +pub mod deploy; +pub mod storage; +pub mod views; #[multiversx_sc::contract] -pub trait ProxyDeployer: farm_deploy::FarmDeployModule { +pub trait ProxyDeployer: deploy::DeployModule + storage::StorageModule + views::ViewModule { + /// Forced deploy args contain the index of the arg, and the argument itself. + /// + /// They must be provided in the order expected by the deployed SCs arguments order. + /// + /// Indexes start from 0 #[init] - fn init(&self, farm_template_address: ManagedAddress) { + fn init( + &self, + template_address: ManagedAddress, + forced_deploy_args: ForcedDeployArgsType, + ) { require!( - self.blockchain().is_smart_contract(&farm_template_address), + self.blockchain().is_smart_contract(&template_address), "Invalid farm template address" ); - self.farm_template_address().set(&farm_template_address); + self.overwrite_forced_deploy_args(forced_deploy_args); + + self.template_address().set(template_address); } #[upgrade] diff --git a/dex/proxy-deployer/src/storage.rs b/dex/proxy-deployer/src/storage.rs new file mode 100644 index 000000000..21c42dc41 --- /dev/null +++ b/dex/proxy-deployer/src/storage.rs @@ -0,0 +1,25 @@ +use crate::deploy::ForcedDeployArg; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait StorageModule { + #[view(getTemplateAddress)] + #[storage_mapper("templateAddress")] + fn template_address(&self) -> SingleValueMapper; + + #[storage_mapper("addressId")] + fn address_id(&self) -> AddressToIdMapper; + + #[storage_mapper("addrForTok")] + fn address_for_token(&self, token_id: &TokenIdentifier) -> SingleValueMapper; + + #[storage_mapper("allUsedTokens")] + fn all_used_tokens(&self) -> UnorderedSetMapper; + + #[storage_mapper("allDeployedContracts")] + fn all_deployed_contracts(&self) -> UnorderedSetMapper; + + #[storage_mapper("forcedDeployArgs")] + fn forced_deploy_args(&self) -> SingleValueMapper>>; +} diff --git a/dex/proxy-deployer/src/views.rs b/dex/proxy-deployer/src/views.rs new file mode 100644 index 000000000..b9ec9ddd1 --- /dev/null +++ b/dex/proxy-deployer/src/views.rs @@ -0,0 +1,81 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[multiversx_sc::module] +pub trait ViewModule: crate::storage::StorageModule { + #[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) + } + + /// 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(getAllDeployedContracts)] + fn get_all_deployed_contracts( + &self, + start_index: usize, + max_entries: usize, + ) -> MultiValueEncoded { + let mapper = self.all_deployed_contracts(); + let ids = self.get_entries(&mapper, start_index, max_entries); + + let id_mapper = self.address_id(); + let mut result = MultiValueEncoded::new(); + for id in ids { + let address = self.get_by_id(&id_mapper, 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 + } + + 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() } + } +} diff --git a/dex/proxy-deployer/wasm/src/lib.rs b/dex/proxy-deployer/wasm/src/lib.rs index 620fcb058..ec41a1894 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: 6 // Async Callback (empty): 1 -// Total number of exported functions: 7 +// Total number of exported functions: 9 #![no_std] @@ -20,10 +20,12 @@ 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 + overwriteForcedDeployArgs => overwrite_forced_deploy_args + deployContract => deploy_contract + getTemplateAddress => template_address + getAddressForToken => get_address_for_token + getAllUsedTokens => get_all_used_tokens + getAllDeployedContracts => get_all_deployed_contracts ) }