diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f765d0a..67c816e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -28,7 +28,7 @@ jobs: - run: rustup target add wasm32-unknown-unknown - uses: taiki-e/install-action@nextest - uses: taiki-e/install-action@just - + - run: sudo apt install libdbus-1-dev pkg-config libudev - name: Run cargo fmt run: cargo fmt --all -- --check - name: build since clippy needs contracts to be built diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c424d39..111e400 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -42,6 +42,7 @@ jobs: key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - run: rustup update - run: rustup target add wasm32-unknown-unknown + - run: sudo apt install libdbus-1-dev pkg-config libudev - uses: taiki-e/install-action@just - uses: taiki-e/install-action@nextest - uses: cargo-bins/cargo-binstall@main diff --git a/crates/loam-sdk-macro/src/subcontract.rs b/crates/loam-sdk-macro/src/subcontract.rs index c3f5d28..7c0c2be 100644 --- a/crates/loam-sdk-macro/src/subcontract.rs +++ b/crates/loam-sdk-macro/src/subcontract.rs @@ -45,28 +45,24 @@ fn generate_method(trait_item: &syn::TraitItem) -> Option { let sig = &method.sig; let name = &sig.ident; let output = &sig.output; - let self_ty = get_receiver(sig.inputs.iter().next()?)?; - + let self_ty = get_receiver(sig.inputs.iter().next()?); let is_result = is_result_type(output); - let args_without_self = get_args_without_self(&sig.inputs); + let args = &args_to_idents(&sig.inputs, self_ty.is_none()); let attrs = &method.attrs; let return_question_mark = if is_result { Some(quote!(?)) } else { None }; - + let Some(self_ty) = self_ty.as_ref() else { + return Some(generate_static_method(sig, attrs, name, args)); + }; if is_mutable_method(self_ty) { Some(generate_mutable_method( sig, attrs, name, - &args_without_self, + args, return_question_mark.as_ref(), )) } else { - Some(generate_immutable_method( - sig, - attrs, - name, - &args_without_self, - )) + Some(generate_immutable_method(sig, attrs, name, args)) } } else { None @@ -81,10 +77,10 @@ fn get_receiver(arg: &syn::FnArg) -> Option<&syn::Receiver> { } } -pub fn get_args_without_self(inputs: &Punctuated) -> Vec { +pub fn args_to_idents(inputs: &Punctuated, is_static: bool) -> Vec { inputs .iter() - .skip(1) + .skip(usize::from(!is_static)) .filter_map(|arg| { if let syn::FnArg::Typed(syn::PatType { pat, .. }) = arg { match &**pat { @@ -101,6 +97,21 @@ pub fn get_args_without_self(inputs: &Punctuated) -> Vec bool { receiver.reference.is_some() && receiver.mutability.is_some() } +fn generate_static_method( + sig: &Signature, + attrs: &[Attribute], + name: &Ident, + args_without_self: &[Ident], +) -> TokenStream { + let inputs = sig.inputs.iter(); + let output = &sig.output; + quote! { + #(#attrs)* + fn #name(#(#inputs),*) #output { + Self::Impl::#name(#(#args_without_self),*) + } + } +} fn generate_immutable_method( sig: &Signature, attrs: &[Attribute], @@ -192,10 +203,10 @@ pub fn derive_contract_impl(args: TokenStream, trait_impls: Item) -> TokenStream .filter_map(|(first, _)| all_traits.get(&format!("Is{first}"))) .flatten() .collect::>(); - + let contract_name = &strukt.ident; for (first, second) in idents { impls.extend(quote! { - impl #first for Contract { + impl #first for #contract_name { type Impl = #second; } }); diff --git a/crates/loam-sdk-macro/src/util.rs b/crates/loam-sdk-macro/src/util.rs index a71b895..31b235f 100644 --- a/crates/loam-sdk-macro/src/util.rs +++ b/crates/loam-sdk-macro/src/util.rs @@ -58,7 +58,7 @@ fn generate_methods(item: &ItemTrait) -> Vec { .filter_map(|item| { if let syn::TraitItem::Fn(TraitItemFn { sig, attrs, .. }) = item { let name = &sig.ident; - Some(generate_method(sig, attrs, name)) + Some(generate_method(sig, attrs, name, sig.receiver().is_none())) } else { None } @@ -70,15 +70,16 @@ fn generate_method( sig: &syn::Signature, attrs: &[syn::Attribute], name: &syn::Ident, + is_static: bool, ) -> TokenStream { let output = &sig.output; - let inputs = sig.inputs.iter().skip(1); - let args_without_self = crate::subcontract::get_args_without_self(&sig.inputs); + let inputs = sig.inputs.iter().skip(usize::from(!is_static)); + let args = crate::subcontract::args_to_idents(&sig.inputs, is_static); quote! { #(#attrs)* pub fn #name(env: loam_sdk::soroban_sdk::Env, #(#inputs),*) #output { loam_sdk::soroban_sdk::set_env(env); - Contract::#name(#(#args_without_self),*) + Contract::#name(#(#args),*) } } } diff --git a/crates/loam-subcontract-core/src/admin.rs b/crates/loam-subcontract-core/src/admin.rs index 2c12c55..3dde25c 100644 --- a/crates/loam-subcontract-core/src/admin.rs +++ b/crates/loam-subcontract-core/src/admin.rs @@ -4,8 +4,14 @@ use loam_sdk::{ }; #[contracttype(export = false)] -#[derive(Default)] -pub struct Admin(Kind); +pub struct Admin(Address); + +impl Default for Admin { + fn default() -> Self { + // Admin should always be initialized in the constructor + unreachable!() + } +} fn admin_key() -> Symbol { symbol_short!("ADMIN") @@ -13,47 +19,31 @@ fn admin_key() -> Symbol { impl Lazy for Admin { fn get_lazy() -> Option { - env().storage().instance().get(&admin_key()) + env().storage().instance().get(&admin_key()).map(Admin) } fn set_lazy(self) { - env().storage().instance().set(&admin_key(), &self); + env().storage().instance().set(&admin_key(), &self.0); } } -/// Work around not having `Option` in `contracttype` -#[contracttype(export = false)] -#[derive(Default)] -pub enum Kind { - Address(Address), - #[default] - None, -} - impl IsCore for Admin { fn admin_get(&self) -> Option
{ - match &self.0 { - Kind::Address(address) => Some(address.clone()), - Kind::None => None, - } + Some(self.0.clone()) } fn admin_set(&mut self, new_admin: Address) { - if let Admin(Kind::Address(admin)) = &self { - admin.require_auth(); - } - self.0 = Kind::Address(new_admin); + self.0.require_auth(); + self.0 = new_admin; } - fn redeploy(&self, wasm_hash: BytesN<32>) { - self.admin_get().unwrap().require_auth(); + fn upgrade(&self, wasm_hash: BytesN<32>) { + self.0.require_auth(); env().deployer().update_current_contract_wasm(wasm_hash); } - fn __constructor(&mut self, admin: Address) { - if self.admin_get().is_none() { - self.admin_set(admin); - } + fn __constructor(admin: Address) { + Self::set_lazy(Self(admin)); } } @@ -66,9 +56,9 @@ pub trait IsCore { /// a different account try to become admin fn admin_set(&mut self, new_admin: loam_sdk::soroban_sdk::Address); - /// Admin can redeploy the contract with given hash. - fn redeploy(&self, wasm_hash: loam_sdk::soroban_sdk::BytesN<32>); + /// Admin can upgrade the contract with given hash. + fn upgrade(&self, wasm_hash: loam_sdk::soroban_sdk::BytesN<32>); /// Constructor to set the admin - fn __constructor(&mut self, admin: loam_sdk::soroban_sdk::Address); + fn __constructor(admin: loam_sdk::soroban_sdk::Address); }