From ad900dad69ed0acf03334e4019c371df5cfdc8f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Pobiarzyn Date: Tue, 25 Nov 2025 10:11:09 +0100 Subject: [PATCH 1/3] Add missing args in factory contract ref --- examples/Odra.toml | 3 ++ examples/src/factory/token.rs | 52 +++++++++++++++++-- odra-macros/src/ast/factory/parts/ref_item.rs | 36 +++++-------- odra-macros/src/ast/ref_utils.rs | 12 +++++ 4 files changed, 77 insertions(+), 26 deletions(-) diff --git a/examples/Odra.toml b/examples/Odra.toml index 0d6ef467..77338526 100644 --- a/examples/Odra.toml +++ b/examples/Odra.toml @@ -93,3 +93,6 @@ fqn = "factory::token::FTokenFactory" [[contracts]] fqn = "factory::token::FToken" + +[[contracts]] +fqn = "factory::token::FactoryProxy" diff --git a/examples/src/factory/token.rs b/examples/src/factory/token.rs index f8a561e7..ad0c66a3 100644 --- a/examples/src/factory/token.rs +++ b/examples/src/factory/token.rs @@ -1,4 +1,4 @@ -use odra::{casper_types::U256, prelude::*}; +use odra::{casper_types::U256, prelude::*, ContractRef}; use odra_modules::{access::Ownable, cep18_token::Cep18}; #[odra::module(factory=on)] @@ -32,17 +32,44 @@ impl FToken { } } +#[odra::module] +pub struct FactoryProxy { + factory_address: Var
+} + +#[odra::module] +impl FactoryProxy { + pub fn init(&mut self, address: Address) { + self.factory_address.set(address); + } + + pub fn deploy_new_contract(&self) -> Address { + let factory_address = self.factory_address.get().unwrap_or_revert(self); + + let mut factory = FTokenFactoryContractRef::new(self.env(), factory_address); + let (addr, _uref) = factory.new_contract( + "TokenContract".to_string(), + "Token".to_string(), + "TTK".to_string(), + 18, + U256::from(1000u64) + ); + addr + } +} + #[cfg(test)] mod tests { use alloc::string::ToString; use odra::{ casper_types::U256, - host::{Deployer, HostRef, NoArgs} + host::{Deployer, HostRef, NoArgs}, + prelude::Addressable }; use crate::factory::token::{ FToken as Token, FTokenFactory as TokenFactory, FTokenHostRef, - FTokenInitArgs as TokenInitArgs + FTokenInitArgs as TokenInitArgs, FactoryProxy, FactoryProxyInitArgs }; #[test] @@ -84,4 +111,23 @@ mod tests { assert_eq!(token.symbol(), "TTK".to_string()); assert_eq!(token.total_supply(), U256::from(500u64)); } + + #[test] + fn test_proxy() { + let env = odra_test::env(); + let factory = TokenFactory::deploy(&env, NoArgs); + let proxy = FactoryProxy::deploy( + &env, + FactoryProxyInitArgs { + address: factory.address() + } + ); + + let addr = proxy.deploy_new_contract(); + let token = FTokenHostRef::new(addr, env); + assert_eq!(token.get_owner(), proxy.address()); + assert_eq!(token.name(), "Token".to_string()); + assert_eq!(token.symbol(), "TTK".to_string()); + assert_eq!(token.total_supply(), U256::from(1000u64)); + } } diff --git a/odra-macros/src/ast/factory/parts/ref_item.rs b/odra-macros/src/ast/factory/parts/ref_item.rs index 50465f23..25d592ea 100644 --- a/odra-macros/src/ast/factory/parts/ref_item.rs +++ b/odra-macros/src/ast/factory/parts/ref_item.rs @@ -31,7 +31,7 @@ impl TryFrom<&'_ ModuleImplIR> for ContractRefImplItem { let fns = vec![module.factory_fn(), module.factory_upgrade_fn(), module.factory_batch_upgrade_fn()]; Ok(Self { ref_ident: module.contract_ref_ident()?, - factory_fns: fns.iter().map(|fun| ref_utils::contract_function_item(fun, false)).collect() + factory_fns: fns.iter().map(|fun| ref_utils::factory_contract_function_item(fun, false)).collect() }) } } @@ -96,15 +96,15 @@ mod test { true, { let mut named_args = odra::casper_types::RuntimeArgs::new(); - if self.attached_value > odra::casper_types::U512::zero() { - let _ = named_args.insert("amount", self.attached_value); - } + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_is_upgradable", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(false, "odra_cfg_is_upgrade", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_allow_key_override", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(contract_name.clone(), "odra_cfg_package_hash_key_name", &mut named_args); odra::args::EntrypointArgument::insert_runtime_arg(contract_name, "contract_name", &mut named_args); odra::args::EntrypointArgument::insert_runtime_arg(value, "value", &mut named_args); named_args } ) - .with_amount(self.attached_value), ) } @@ -120,18 +120,13 @@ mod test { true, { let mut named_args = odra::casper_types::RuntimeArgs::new(); - if self.attached_value > odra::casper_types::U512::zero() { - let _ = named_args.insert("amount", self.attached_value); - } - odra::args::EntrypointArgument::insert_runtime_arg( - contract_name, - "contract_name", - &mut named_args, - ); + odra::args::EntrypointArgument::insert_runtime_arg(contract_name, "contract_name", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_is_factory_upgrade", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_allow_key_override", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(false, "odra_cfg_create_upgrade_group", &mut named_args); named_args }, ) - .with_amount(self.attached_value), ) } @@ -151,18 +146,13 @@ mod test { true, { let mut named_args = odra::casper_types::RuntimeArgs::new(); - if self.attached_value > odra::casper_types::U512::zero() { - let _ = named_args.insert("amount", self.attached_value); - } - odra::args::EntrypointArgument::insert_runtime_arg( - odra::args::BatchUpgradeArgs::from(args), - "args", - &mut named_args, - ); + odra::args::EntrypointArgument::insert_runtime_arg(odra::args::BatchUpgradeArgs::from(args), "args", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_is_factory_upgrade", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_allow_key_override", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(false, "odra_cfg_create_upgrade_group", &mut named_args); named_args }, ) - .with_amount(self.attached_value), ) } } diff --git a/odra-macros/src/ast/ref_utils.rs b/odra-macros/src/ast/ref_utils.rs index 0cd7bbbf..9ca746db 100644 --- a/odra-macros/src/ast/ref_utils.rs +++ b/odra-macros/src/ast/ref_utils.rs @@ -57,6 +57,18 @@ pub fn contract_function_item(fun: &FnIR, is_trait_impl: bool) -> syn::ItemFn { env_call(signature, call_def_expr, attrs, vis) } +pub fn factory_contract_function_item(fun: &FnIR, is_trait_impl: bool) -> syn::ItemFn { + let vis = match is_trait_impl { + true => visibility_default(), + false => visibility_pub() + }; + let signature = function_signature(fun); + let call_def_expr = factory_call_def_with_amount(fun); + let attrs = function_filtered_attrs(fun); + + env_call(signature, call_def_expr, attrs, vis) +} + fn env_call( sig: syn::Signature, call_def_expr: syn::Expr, From 515b92b8d4d9ef06c1dda7c1639f73e2d00b90d7 Mon Sep 17 00:00:00 2001 From: Krzysztof Pobiarzyn Date: Tue, 25 Nov 2025 10:12:10 +0100 Subject: [PATCH 2/3] Ignore proxy test in odra vm environment --- examples/src/factory/token.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/src/factory/token.rs b/examples/src/factory/token.rs index ad0c66a3..b1c3f8b0 100644 --- a/examples/src/factory/token.rs +++ b/examples/src/factory/token.rs @@ -113,6 +113,7 @@ mod tests { } #[test] + #[ignore = "This test does not work on odra vm"] fn test_proxy() { let env = odra_test::env(); let factory = TokenFactory::deploy(&env, NoArgs); From 5207dbb384a9b440de68297fc7d5b80a9b9ac854 Mon Sep 17 00:00:00 2001 From: Krzysztof Pobiarzyn Date: Tue, 25 Nov 2025 14:20:51 +0100 Subject: [PATCH 3/3] Refactor factory contract functions to remove unnecessary caller override and streamline argument handling --- odra-casper/wasm-env/src/host_functions.rs | 5 ---- odra-macros/src/ast/factory/impl_item.rs | 25 ++++++++----------- .../src/ast/factory/parts/wasm_parts.rs | 12 ++++++--- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/odra-casper/wasm-env/src/host_functions.rs b/odra-casper/wasm-env/src/host_functions.rs index 3e2d6b57..b7f18bf9 100644 --- a/odra-casper/wasm-env/src/host_functions.rs +++ b/odra-casper/wasm-env/src/host_functions.rs @@ -148,11 +148,6 @@ pub fn install_new_contract( let contract_package_hash = ContractPackageHash::new(contract_hash.value()); if has_init { - if is_factory { - unsafe { - CALLER_OVERRIDE = true; - } - } let init_access = create_contract_user_group(contract_package_hash, CONSTRUCTOR_GROUP_NAME); let _: () = runtime::call_versioned_contract( contract_package_hash, diff --git a/odra-macros/src/ast/factory/impl_item.rs b/odra-macros/src/ast/factory/impl_item.rs index eecb0e9e..a4d349ae 100644 --- a/odra-macros/src/ast/factory/impl_item.rs +++ b/odra-macros/src/ast/factory/impl_item.rs @@ -125,15 +125,15 @@ mod test { true, { let mut named_args = odra::casper_types::RuntimeArgs::new(); - if self.attached_value > odra::casper_types::U512::zero() { - let _ = named_args.insert("amount", self.attached_value); - } + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_is_upgradable", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(false, "odra_cfg_is_upgrade", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_allow_key_override", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(contract_name.clone(), "odra_cfg_package_hash_key_name", &mut named_args); odra::args::EntrypointArgument::insert_runtime_arg(contract_name, "contract_name", &mut named_args); odra::args::EntrypointArgument::insert_runtime_arg(value, "value", &mut named_args); named_args } ) - .with_amount(self.attached_value), ) } @@ -145,14 +145,13 @@ mod test { true, { let mut named_args = odra::casper_types::RuntimeArgs::new(); - if self.attached_value > odra::casper_types::U512::zero() { - let _ = named_args.insert("amount", self.attached_value); - } odra::args::EntrypointArgument::insert_runtime_arg(contract_name, "contract_name", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_is_factory_upgrade", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_allow_key_override", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(false, "odra_cfg_create_upgrade_group", &mut named_args); named_args } ) - .with_amount(self.attached_value), ) } @@ -166,14 +165,13 @@ mod test { true, { let mut named_args = odra::casper_types::RuntimeArgs::new(); - if self.attached_value > odra::casper_types::U512::zero() { - let _ = named_args.insert("amount", self.attached_value); - } odra::args::EntrypointArgument::insert_runtime_arg(odra::args::BatchUpgradeArgs::from(args), "args", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_is_factory_upgrade", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(true, "odra_cfg_allow_key_override", &mut named_args); + odra::args::EntrypointArgument::insert_runtime_arg(false, "odra_cfg_create_upgrade_group", &mut named_args); named_args } ) - .with_amount(self.attached_value), ) } } @@ -632,7 +630,6 @@ mod test { #[no_mangle] fn total_supply() { - odra::odra_casper_wasm_env::host_functions::override_factory_caller(); let result = __erc20_factory_exec_parts::execute_total_supply(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); odra::odra_casper_wasm_env::casper_contract::contract_api::runtime::ret( odra::odra_casper_wasm_env::casper_contract::unwrap_or_revert::UnwrapOrRevert::unwrap_or_revert( @@ -643,13 +640,11 @@ mod test { #[no_mangle] fn pay_to_mint() { - odra::odra_casper_wasm_env::host_functions::override_factory_caller(); __erc20_factory_exec_parts::execute_pay_to_mint(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); } #[no_mangle] fn approve() { - odra::odra_casper_wasm_env::host_functions::override_factory_caller(); __erc20_factory_exec_parts::execute_approve(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); } } diff --git a/odra-macros/src/ast/factory/parts/wasm_parts.rs b/odra-macros/src/ast/factory/parts/wasm_parts.rs index 438421b9..d45dcd61 100644 --- a/odra-macros/src/ast/factory/parts/wasm_parts.rs +++ b/odra-macros/src/ast/factory/parts/wasm_parts.rs @@ -5,6 +5,7 @@ use syn::parse_quote; use crate::ast::parts_utils::{UsePreludeItem, UseSuperItem}; use crate::ast::wasm_parts::{NoMangleFnItem, NoMangleItemContext}; use crate::ast::wasm_parts_utils; +use crate::ir::FnType; use crate::utils::misc::AsType; use crate::{ ast::fn_utils, @@ -35,9 +36,15 @@ impl TryFrom<(&'_ ModuleImplIR, &'_ FnIR)> for NoMangleFnItem { syn::ReturnType::Type(_, _) => Some(utils::stmt::runtime_return(&result_ident)) }; + let override_stmt = if [FnType::Constructor, FnType::Upgrader].contains(&func.fn_type()) { + Some(parse_quote!(odra::odra_casper_wasm_env::host_functions::override_factory_caller();)) + } else { + None + }; + Ok(Self { sig: parse_quote!(fn #fn_ident()), - override_stmt: Some(parse_quote!(odra::odra_casper_wasm_env::host_functions::override_factory_caller();)), + override_stmt, execute_stmt, ret_stmt, ctx: std::marker::PhantomData:: @@ -745,7 +752,6 @@ mod test { #[no_mangle] fn total_supply() { - odra::odra_casper_wasm_env::host_functions::override_factory_caller(); let result = __erc20_factory_exec_parts::execute_total_supply(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); odra::odra_casper_wasm_env::casper_contract::contract_api::runtime::ret( odra::odra_casper_wasm_env::casper_contract::unwrap_or_revert::UnwrapOrRevert::unwrap_or_revert( @@ -756,13 +762,11 @@ mod test { #[no_mangle] fn pay_to_mint() { - odra::odra_casper_wasm_env::host_functions::override_factory_caller(); __erc20_factory_exec_parts::execute_pay_to_mint(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); } #[no_mangle] fn approve() { - odra::odra_casper_wasm_env::host_functions::override_factory_caller(); __erc20_factory_exec_parts::execute_approve(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); } }