Skip to content

Commit

Permalink
impl
Browse files Browse the repository at this point in the history
  • Loading branch information
dorin-iancu committed Nov 26, 2024
1 parent a26137a commit 8fd716c
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 98 deletions.
134 changes: 134 additions & 0 deletions dex/proxy-deployer/src/deploy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem)]
pub struct ForcedDeployArg<M: ManagedTypeApi> {
pub arg_nr: usize,
pub value: ManagedBuffer<M>,
}

pub type ForcedDeployArgsType<M> = MultiValueEncoded<M, MultiValue2<usize, ManagedBuffer<M>>>;

#[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<Self::Api>) {
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<ManagedBuffer>,
) -> 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<ManagedBuffer>,
) -> ManagedArgBuffer<Self::Api> {
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<ForcedDeployArg<Self::Api>>,
) -> Option<ForcedDeployArg<Self::Api>> {
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<Self::Api>) -> 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
}
}
87 changes: 0 additions & 87 deletions dex/proxy-deployer/src/farm_deploy.rs

This file was deleted.

25 changes: 20 additions & 5 deletions dex/proxy-deployer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<Self::Api>,
) {
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]
Expand Down
25 changes: 25 additions & 0 deletions dex/proxy-deployer/src/storage.rs
Original file line number Diff line number Diff line change
@@ -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<ManagedAddress>;

#[storage_mapper("addressId")]
fn address_id(&self) -> AddressToIdMapper;

#[storage_mapper("addrForTok")]
fn address_for_token(&self, token_id: &TokenIdentifier) -> SingleValueMapper<AddressId>;

#[storage_mapper("allUsedTokens")]
fn all_used_tokens(&self) -> UnorderedSetMapper<TokenIdentifier>;

#[storage_mapper("allDeployedContracts")]
fn all_deployed_contracts(&self) -> UnorderedSetMapper<AddressId>;

#[storage_mapper("forcedDeployArgs")]
fn forced_deploy_args(&self) -> SingleValueMapper<ManagedVec<ForcedDeployArg<Self::Api>>>;
}
81 changes: 81 additions & 0 deletions dex/proxy-deployer/src/views.rs
Original file line number Diff line number Diff line change
@@ -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<ManagedAddress> {
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<TokenIdentifier> {
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<ManagedAddress> {
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<T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static>(
&self,
mapper: &UnorderedSetMapper<T>,
start_index: usize,
max_entries: usize,
) -> MultiValueEncoded<T> {
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() }
}
}
14 changes: 8 additions & 6 deletions dex/proxy-deployer/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand All @@ -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
)
}

Expand Down

0 comments on commit 8fd716c

Please sign in to comment.