From 2d49ebd2abf9097f3aac67b318fbd13abfe791e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Pobiar=C5=BCyn?= Date: Mon, 8 Jan 2024 07:50:16 +0100 Subject: [PATCH] Accept a slice as an entry point arg (#302) --- modules/src/erc1155/erc1155_base.rs | 2 +- modules/src/erc1155/mod.rs | 2 +- modules/src/erc1155/owned_erc1155.rs | 2 +- modules/src/erc1155_token.rs | 2 +- odra-macros/src/ast/deployer_item.rs | 4 ++++ odra-macros/src/ast/entrypoints_item.rs | 21 +++++++++++++++++ odra-macros/src/ast/exec_parts.rs | 30 ++++++++++++++++++++----- odra-macros/src/ast/host_ref_item.rs | 22 ++++++++++++++++++ odra-macros/src/ast/ref_item.rs | 16 +++++++++++++ odra-macros/src/ast/test_parts.rs | 26 +++++++++++++++++++++ odra-macros/src/ast/wasm_parts.rs | 20 +++++++++++++++++ odra-macros/src/ir/mod.rs | 2 +- odra-macros/src/test_utils.rs | 3 +++ odra-macros/src/utils/expr.rs | 2 +- odra-macros/src/utils/stmt.rs | 4 ++-- odra-macros/src/utils/syn.rs | 7 ------ odra-macros/src/utils/ty.rs | 20 +++++++++++++++++ 17 files changed, 164 insertions(+), 21 deletions(-) diff --git a/modules/src/erc1155/erc1155_base.rs b/modules/src/erc1155/erc1155_base.rs index b293c897..833b4a8a 100644 --- a/modules/src/erc1155/erc1155_base.rs +++ b/modules/src/erc1155/erc1155_base.rs @@ -18,7 +18,7 @@ impl Erc1155 for Erc1155Base { self.balances.get_or_default(&(*owner, *id)) } - fn balance_of_batch(&self, owners: Vec
, ids: Vec) -> Vec { + fn balance_of_batch(&self, owners: &[Address], ids: &[U256]) -> Vec { if owners.len() != ids.len() { self.env().revert(Error::AccountsAndIdsLengthMismatch); } diff --git a/modules/src/erc1155/mod.rs b/modules/src/erc1155/mod.rs index fd68c540..4a51b929 100644 --- a/modules/src/erc1155/mod.rs +++ b/modules/src/erc1155/mod.rs @@ -13,7 +13,7 @@ pub trait Erc1155 { /// Batched version of [Erc1155::balance_of](Self::balance_of). /// /// The length of `owners` and `ids` must be the same. - fn balance_of_batch(&self, owners: Vec
, ids: Vec) -> Vec; + fn balance_of_batch(&self, owners: &[Address], ids: &[U256]) -> Vec; /// Allows or denials the `operator` to transfer the caller’s tokens. /// /// Emits [crate::erc1155::events::ApprovalForAll]. diff --git a/modules/src/erc1155/owned_erc1155.rs b/modules/src/erc1155/owned_erc1155.rs index a255f2dd..3730e5e8 100644 --- a/modules/src/erc1155/owned_erc1155.rs +++ b/modules/src/erc1155/owned_erc1155.rs @@ -28,7 +28,7 @@ pub trait OwnedErc1155 { /// Batched version of [Erc1155::balance_of](Self::balance_of). /// /// The length of `owners` and `ids` must be the same. - fn balance_of_batch(&self, owners: Vec
, ids: Vec) -> Vec; + fn balance_of_batch(&self, owners: &[Address], ids: &[U256]) -> Vec; /// Allows or denials the `operator` to transfer the caller’s tokens. /// /// Emits [crate::erc1155::events::ApprovalForAll]. diff --git a/modules/src/erc1155_token.rs b/modules/src/erc1155_token.rs index 23ffe77e..3e9fcd01 100644 --- a/modules/src/erc1155_token.rs +++ b/modules/src/erc1155_token.rs @@ -25,7 +25,7 @@ impl OwnedErc1155 for Erc1155Token { fn balance_of(&self, owner: &Address, id: &U256) -> U256 { self.core.balance_of(owner, id) } - fn balance_of_batch(&self, owners: Vec
, ids: Vec) -> Vec { + fn balance_of_batch(&self, owners: &[Address], ids: &[U256]) -> Vec { self.core.balance_of_batch(owners, ids) } fn set_approval_for_all(&mut self, operator: &Address, approved: bool) { diff --git a/odra-macros/src/ast/deployer_item.rs b/odra-macros/src/ast/deployer_item.rs index 9f8ac768..9d31bf09 100644 --- a/odra-macros/src/ast/deployer_item.rs +++ b/odra-macros/src/ast/deployer_item.rs @@ -106,6 +106,10 @@ mod deployer_impl { let result = __erc20_exec_parts::execute_approve(contract_env); odra::ToBytes::to_bytes(&result).map(Into::into).unwrap() } + "airdrop" => { + let result = execute_airdrop(contract_env); + odra::ToBytes::to_bytes(&result).map(Into::into).unwrap() + } _ => panic!("Unknown method") } }); diff --git a/odra-macros/src/ast/entrypoints_item.rs b/odra-macros/src/ast/entrypoints_item.rs index beb160b2..d5864c7f 100644 --- a/odra-macros/src/ast/entrypoints_item.rs +++ b/odra-macros/src/ast/entrypoints_item.rs @@ -182,6 +182,27 @@ mod test { ret: <() as odra::casper_types::CLTyped>::cl_type(), ty: odra::contract_def::EntrypointType::Public, attributes: vec![odra::contract_def::EntrypointAttribute::NonReentrant] + }, + odra::contract_def::Entrypoint { + ident: String::from("airdrop"), + args: vec![ + odra::contract_def::Argument { + ident: String::from("to"), + ty: as odra::casper_types::CLTyped>::cl_type(), + is_ref: false, + is_slice: false + }, + odra::contract_def::Argument { + ident: String::from("amount"), + ty: ::cl_type(), + is_ref: false, + is_slice: false + } + ], + is_mut: false, + ret: <() as odra::casper_types::CLTyped>::cl_type(), + ty: odra::contract_def::EntrypointType::Public, + attributes: vec![] } ] } diff --git a/odra-macros/src/ast/exec_parts.rs b/odra-macros/src/ast/exec_parts.rs index 5fb6e3f0..5ec959cc 100644 --- a/odra-macros/src/ast/exec_parts.rs +++ b/odra-macros/src/ast/exec_parts.rs @@ -91,10 +91,17 @@ impl TryFrom<(&'_ ModuleImplIR, &'_ FnIR)> for ExecFunctionItem { }).collect::, syn::Error>>()?; let args = func - .arg_names() + .named_args() .iter() - .map(|ident| utils::stmt::get_named_arg(ident, &exec_env_ident)) - .collect(); + .map(|arg| { + let ty = utils::ty::unreferenced_ty(&arg.ty()?); + Ok(utils::stmt::get_named_arg( + &arg.name()?, + &exec_env_ident, + &ty + )) + }) + .collect::, syn::Error>>()?; let init_contract_stmt = match func.is_mut() { true => utils::stmt::new_mut_module(&contract_ident, &module_ident, &env_rc_ident), @@ -219,7 +226,7 @@ mod test { pub fn execute_init(env: odra::ContractEnv) { let env_rc = Rc::new(env); let exec_env = odra::ExecutionEnv::new(env_rc.clone()); - let total_supply = exec_env.get_named_arg("total_supply"); + let total_supply = exec_env.get_named_arg::>("total_supply"); let mut contract = ::new(env_rc); let result = contract.init(total_supply); return result; @@ -249,13 +256,24 @@ mod test { let env_rc = Rc::new(env); let exec_env = odra::ExecutionEnv::new(env_rc.clone()); exec_env.non_reentrant_before(); - let to = exec_env.get_named_arg("to"); - let amount = exec_env.get_named_arg("amount"); + let to = exec_env.get_named_arg::
("to"); + let amount = exec_env.get_named_arg::("amount"); let mut contract = ::new(env_rc); let result = contract.approve(&to, &amount); exec_env.non_reentrant_after(); return result; } + + #[inline] + pub fn execute_airdrop(env: odra::ContractEnv) { + let env_rc = Rc::new(env); + let exec_env = odra::ExecutionEnv::new(env_rc.clone()); + let to = exec_env.get_named_arg::>("to"); + let amount = exec_env.get_named_arg::("amount"); + let contract = ::new(env_rc); + let result = contract.airdrop(&to, &amount); + return result; + } } }; diff --git a/odra-macros/src/ast/host_ref_item.rs b/odra-macros/src/ast/host_ref_item.rs index 5bebdeca..653d438a 100644 --- a/odra-macros/src/ast/host_ref_item.rs +++ b/odra-macros/src/ast/host_ref_item.rs @@ -258,6 +258,28 @@ mod ref_item_tests { pub fn approve(&mut self, to: Address, amount: U256) { self.try_approve(to, amount).unwrap() } + + pub fn try_airdrop(&self, to: odra::prelude::vec::Vec
, amount: U256) -> Result<(), odra::OdraError> { + self.env.call_contract( + self.address, + odra::CallDef::new( + String::from("airdrop"), + { + let mut named_args = odra::RuntimeArgs::new(); + if self.attached_value > odra::U512::zero() { + let _ = named_args.insert("amount", self.attached_value); + } + let _ = named_args.insert("to", to); + let _ = named_args.insert("amount", amount); + named_args + } + ).with_amount(self.attached_value), + ) + } + + pub fn airdrop(&self, to: odra::prelude::vec::Vec
, amount: U256) { + self.try_airdrop(to, amount).unwrap() + } } }; let actual = HostRefItem::try_from(&module).unwrap(); diff --git a/odra-macros/src/ast/ref_item.rs b/odra-macros/src/ast/ref_item.rs index fa43d8a8..555542e3 100644 --- a/odra-macros/src/ast/ref_item.rs +++ b/odra-macros/src/ast/ref_item.rs @@ -203,6 +203,22 @@ mod ref_item_tests { ), ) } + + pub fn airdrop(&self, to: odra::prelude::vec::Vec
, amount: U256) { + self.env + .call_contract( + self.address, + odra::CallDef::new( + String::from("airdrop"), + { + let mut named_args = odra::RuntimeArgs::new(); + let _ = named_args.insert("to", to); + let _ = named_args.insert("amount", amount); + named_args + }, + ), + ) + } } }; let actual = RefItem::try_from(&module).unwrap(); diff --git a/odra-macros/src/ast/test_parts.rs b/odra-macros/src/ast/test_parts.rs index 9387c956..d037e329 100644 --- a/odra-macros/src/ast/test_parts.rs +++ b/odra-macros/src/ast/test_parts.rs @@ -168,6 +168,28 @@ mod test { pub fn approve(&mut self, to: Address, amount: U256) { self.try_approve(to, amount).unwrap() } + + pub fn try_airdrop(&self, to: odra::prelude::vec::Vec
, amount: U256) -> Result<(), odra::OdraError> { + self.env.call_contract( + self.address, + odra::CallDef::new( + String::from("airdrop"), + { + let mut named_args = odra::RuntimeArgs::new(); + if self.attached_value > odra::U512::zero() { + let _ = named_args.insert("amount", self.attached_value); + } + let _ = named_args.insert("to", to); + let _ = named_args.insert("amount", amount); + named_args + } + ).with_amount(self.attached_value), + ) + } + + pub fn airdrop(&self, to: odra::prelude::vec::Vec
, amount: U256) { + self.try_airdrop(to, amount).unwrap() + } } pub struct Erc20Deployer; @@ -192,6 +214,10 @@ mod test { let result = __erc20_exec_parts::execute_approve(contract_env); odra::ToBytes::to_bytes(&result).map(Into::into).unwrap() } + "airdrop" => { + let result = execute_airdrop(contract_env); + odra::ToBytes::to_bytes(&result).map(Into::into).unwrap() + } _ => panic!("Unknown method") } }); diff --git a/odra-macros/src/ast/wasm_parts.rs b/odra-macros/src/ast/wasm_parts.rs index 753ac6fa..522eb08b 100644 --- a/odra-macros/src/ast/wasm_parts.rs +++ b/odra-macros/src/ast/wasm_parts.rs @@ -320,6 +320,21 @@ mod test { ), ); entry_points + .add_entry_point( + odra::casper_types::EntryPoint::new( + "airdrop", + vec![ + odra::casper_types::Parameter::new("to", as + odra::casper_types::CLTyped > ::cl_type()), + odra::casper_types::Parameter::new("amount", ::cl_type()) + ], + <() as odra::casper_types::CLTyped>::cl_type(), + odra::casper_types::EntryPointAccess::Public, + odra::casper_types::EntryPointType::Contract, + ), + ); + entry_points } #[no_mangle] @@ -366,6 +381,11 @@ mod test { fn approve() { __erc20_exec_parts::execute_approve(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); } + + #[no_mangle] + fn airdrop() { + execute_airdrop(odra::odra_casper_wasm_env::WasmContractEnv::new_env()); + } } }; diff --git a/odra-macros/src/ir/mod.rs b/odra-macros/src/ir/mod.rs index da0d3047..ccd4a64b 100644 --- a/odra-macros/src/ir/mod.rs +++ b/odra-macros/src/ir/mod.rs @@ -437,7 +437,7 @@ impl FnIR { self.typed_args() .into_iter() .map(|pat_ty| syn::PatType { - ty: Box::new(utils::syn::unreferenced_ty(&pat_ty.ty)), + ty: Box::new(utils::ty::unreferenced_ty(&pat_ty.ty)), ..pat_ty }) .collect() diff --git a/odra-macros/src/test_utils.rs b/odra-macros/src/test_utils.rs index d29005f6..0b2ef5e0 100644 --- a/odra-macros/src/test_utils.rs +++ b/odra-macros/src/test_utils.rs @@ -34,6 +34,9 @@ pub mod mock { }); } + pub fn airdrop(to: &[Address], amount: &U256) { + } + fn private_function() { } diff --git a/odra-macros/src/utils/expr.rs b/odra-macros/src/utils/expr.rs index d80f41e0..b5c28538 100644 --- a/odra-macros/src/utils/expr.rs +++ b/odra-macros/src/utils/expr.rs @@ -52,7 +52,7 @@ pub fn new_parameter(name: String, ty: syn::Type) -> syn::Expr { } pub fn as_cl_type(ty: &syn::Type) -> syn::Expr { - let ty = super::syn::unreferenced_ty(ty); + let ty = super::ty::unreferenced_ty(ty); let ty_cl_typed = super::ty::cl_typed(); let ty = super::syn::as_casted_ty_stream(&ty, ty_cl_typed); parse_quote!(#ty::cl_type()) diff --git a/odra-macros/src/utils/stmt.rs b/odra-macros/src/utils/stmt.rs index 8ef59b27..3dcec07c 100644 --- a/odra-macros/src/utils/stmt.rs +++ b/odra-macros/src/utils/stmt.rs @@ -39,9 +39,9 @@ pub fn install_contract(entry_points: syn::Expr, schemas: syn::Expr, args: syn:: );) } -pub fn get_named_arg(arg_ident: &syn::Ident, env_ident: &syn::Ident) -> syn::Stmt { +pub fn get_named_arg(arg_ident: &syn::Ident, env_ident: &syn::Ident, ty: &syn::Type) -> syn::Stmt { let arg_name = arg_ident.to_string(); - parse_quote!(let #arg_ident = #env_ident.get_named_arg(#arg_name);) + parse_quote!(let #arg_ident = #env_ident.get_named_arg::<#ty>(#arg_name);) } pub fn new_execution_env(ident: &syn::Ident, env_rc_ident: &syn::Ident) -> syn::Stmt { diff --git a/odra-macros/src/utils/syn.rs b/odra-macros/src/utils/syn.rs index 15c0ff79..5346ff54 100644 --- a/odra-macros/src/utils/syn.rs +++ b/odra-macros/src/utils/syn.rs @@ -191,13 +191,6 @@ pub fn is_ref(ty: &syn::Type) -> bool { matches!(ty, syn::Type::Reference(_)) } -pub fn unreferenced_ty(ty: &syn::Type) -> syn::Type { - match ty { - syn::Type::Reference(syn::TypeReference { elem, .. }) => *elem.clone(), - _ => ty.clone() - } -} - fn clear_path(ty: &syn::TypePath) -> syn::Result { let mut owned_ty = ty.to_owned(); diff --git a/odra-macros/src/utils/ty.rs b/odra-macros/src/utils/ty.rs index 5c6899ce..da99f25f 100644 --- a/odra-macros/src/utils/ty.rs +++ b/odra-macros/src/utils/ty.rs @@ -236,3 +236,23 @@ pub fn typed_btree_map(key: &syn::Type, value: &syn::Type) -> syn::Type { pub fn btree_map() -> syn::Type { parse_quote!(odra::prelude::BTreeMap) } + +fn slice_to_vec(ty: &syn::Type) -> syn::Type { + match ty { + syn::Type::Slice(ty) => vec_of(ty.elem.as_ref()), + _ => ty.clone() + } +} + +pub fn unreferenced_ty(ty: &syn::Type) -> syn::Type { + match ty { + syn::Type::Reference(syn::TypeReference { elem, .. }) => { + if matches!(**elem, syn::Type::Reference(_)) { + unreferenced_ty(elem) + } else { + slice_to_vec(elem) + } + } + _ => slice_to_vec(ty) + } +}