diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index e4821480a6..9ef99b295b 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -319,16 +319,18 @@ where /// - If the instantiation process runs out of gas. /// - If given insufficient endowment. /// - If the returned account ID failed to decode properly. -pub fn instantiate_contract( +pub fn instantiate_contract( params: &CreateParams, -) -> Result +) -> Result +// ) -> Result where E: Environment, Args: scale::Encode, Salt: AsRef<[u8]>, + R: scale::Decode, { ::on_instance(|instance| { - TypedEnvBackend::instantiate_contract::(instance, params) + TypedEnvBackend::instantiate_contract::(instance, params) }) } diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index dc3a8832b0..7988979acb 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -439,14 +439,16 @@ pub trait TypedEnvBackend: EnvBackend { /// # Note /// /// For more details visit: [`instantiate_contract`][`crate::instantiate_contract`] - fn instantiate_contract( + fn instantiate_contract( &mut self, params: &CreateParams, - ) -> Result + ) -> Result + // ) -> Result where E: Environment, Args: scale::Encode, - Salt: AsRef<[u8]>; + Salt: AsRef<[u8]>, + R: scale::Decode; /// Terminates a smart contract. /// diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index c723dd9e1c..603c9848fd 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -116,12 +116,13 @@ where E: Environment, Args: scale::Encode, Salt: AsRef<[u8]>, - R: FromAccountId, + R: scale::Decode, + // R: FromAccountId, { /// Instantiates the contract and returns its account ID back to the caller. #[inline] pub fn instantiate(&self) -> Result { - crate::instantiate_contract(self).map(FromAccountId::from_account_id) + crate::instantiate_contract(self) //.map(FromAccountId::from_account_id) } } @@ -135,7 +136,7 @@ where endowment: Endowment, exec_input: Args, salt: Salt, - return_type: ReturnType, + return_type: R, _phantom: PhantomData E>, } @@ -195,11 +196,12 @@ pub fn build_create() -> CreateBuilder< Unset, Unset>, Unset, - R, + Unset>, > where E: Environment, - R: FromAccountId, + R: scale::Decode, + // R: FromAccountId, { CreateBuilder { code_hash: Default::default(), @@ -281,6 +283,34 @@ where } } +impl + CreateBuilder>> +where + E: Environment, +{ + /// Sets the type of the returned value upon the execution of the call. + /// + /// # Note + /// + /// Either use `.returns::<()>` to signal that the call does not return a value + /// or use `.returns::` to signal that the call returns a value of type `T`. + #[inline] + pub fn returns( + self, + ) -> CreateBuilder>> + { + CreateBuilder { + code_hash: self.code_hash, + gas_limit: self.gas_limit, + endowment: self.endowment, + exec_input: self.exec_input, + salt: self.salt, + return_type: Set(Default::default()), + _phantom: Default::default(), + } + } +} + impl CreateBuilder< E, @@ -347,7 +377,7 @@ impl Set, Set>, Set, - R, + Set>, > where E: Environment, @@ -362,7 +392,7 @@ where endowment: self.endowment.value(), exec_input: self.exec_input.value(), salt_bytes: self.salt.value(), - _return_type: self.return_type, + _return_type: Default::default(), } } } @@ -375,14 +405,15 @@ impl Set, Set>, Set, - R, + Set>, > where E: Environment, GasLimit: Unwrap, Args: scale::Encode, Salt: AsRef<[u8]>, - R: FromAccountId, + R: scale::Decode, + // R: FromAccountId, { /// Instantiates the contract using the given instantiation parameters. #[inline] diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 6954942e69..e662578dd0 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -469,14 +469,16 @@ impl TypedEnvBackend for EnvInstance { ) } - fn instantiate_contract( + fn instantiate_contract( &mut self, params: &CreateParams, - ) -> Result + ) -> Result + // ) -> Result where E: Environment, Args: scale::Encode, Salt: AsRef<[u8]>, + R: scale::Decode, { let _code_hash = params.code_hash(); let _gas_limit = params.gas_limit(); diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 036bb16d87..977409ded2 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -479,14 +479,16 @@ impl TypedEnvBackend for EnvInstance { } } - fn instantiate_contract( + fn instantiate_contract( &mut self, params: &CreateParams, - ) -> Result + ) -> Result + // ) -> Result where E: Environment, Args: scale::Encode, Salt: AsRef<[u8]>, + R: scale::Decode, { let mut scoped = self.scoped_buffer(); let gas_limit = params.gas_limit(); @@ -503,7 +505,9 @@ impl TypedEnvBackend for EnvInstance { // This should change in the future but for that we need to add support // for constructors that may return values. // This is useful to support fallible constructors for example. - ext::instantiate( + // + // TODO: Support this output buffer? + let instantiate_result = ext::instantiate( enc_code_hash, gas_limit, enc_endowment, @@ -511,9 +515,31 @@ impl TypedEnvBackend for EnvInstance { out_address, out_return_value, salt, - )?; - let account_id = scale::Decode::decode(&mut &out_address[..])?; - Ok(account_id) + ); + + match instantiate_result { + Ok(()) => { + // The Ok case always needs to decode into an address + // + // This decodes to an `E::AccountId` + // + // But here I want an `Ok(E::AccountId)` + let account_id = scale::Decode::decode(&mut &out_address[..])?; + Ok(account_id) + + // let out = scale::Decode::decode(&mut &out_return_value[..])?; + // Ok(out) + } + Err(ext::Error::CalleeReverted) => { + // This decodes to an `Err(CouldNotReadInput)` + let out = scale::Decode::decode(&mut &out_return_value[..])?; + Ok(out) + } + Err(actual_error) => Err(actual_error.into()), + } + + // let account_id = scale::Decode::decode(&mut &out_address[..])?; + // Ok(account_id) } fn terminate_contract(&mut self, beneficiary: E::AccountId) -> ! diff --git a/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs b/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs index 588d14fd8a..6e176b58c6 100644 --- a/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs +++ b/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs @@ -403,6 +403,7 @@ impl ContractRef<'_> { let input_bindings = generator::input_bindings(constructor.inputs()); let input_types = generator::input_types(constructor.inputs()); let arg_list = generator::generate_argument_list(input_types.iter().cloned()); + let return_type = constructor.wrapped_output(); quote_spanned!(span => #( #attrs )* #[inline] @@ -416,9 +417,10 @@ impl ContractRef<'_> { ::ink::env::call::utils::Unset, ::ink::env::call::utils::Set<::ink::env::call::ExecutionInput<#arg_list>>, ::ink::env::call::utils::Unset<::ink::env::call::state::Salt>, - Self, + ::ink::env::call::utils::Unset<::ink::env::call::utils::ReturnType<#return_type>>, + // Self, > { - ::ink::env::call::build_create::() + ::ink::env::call::build_create::() .exec_input( ::ink::env::call::ExecutionInput::new( ::ink::env::call::Selector::new([ #( #selector_bytes ),* ]) diff --git a/crates/ink/ir/src/ir/item_impl/constructor.rs b/crates/ink/ir/src/ir/item_impl/constructor.rs index 72bb1d3acb..d1d326ad5e 100644 --- a/crates/ink/ir/src/ir/item_impl/constructor.rs +++ b/crates/ink/ir/src/ir/item_impl/constructor.rs @@ -236,7 +236,7 @@ impl Constructor { let return_type = self .output() .map(quote::ToTokens::to_token_stream) - .unwrap_or_else(|| quote::quote! { () }); + .unwrap_or_else(|| quote::quote! { Self }); syn::parse_quote! { ::ink::ConstructorResult<#return_type> diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 1afdfbe839..7218cf6cdd 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -469,15 +469,17 @@ where /// # Note /// /// For more details visit: [`ink_env::instantiate_contract`] - pub fn instantiate_contract( + pub fn instantiate_contract( self, params: &CreateParams, - ) -> Result + ) -> Result + // ) -> Result where Args: scale::Encode, Salt: AsRef<[u8]>, + R: scale::Decode, { - ink_env::instantiate_contract::(params) + ink_env::instantiate_contract::(params) } /// Invokes a contract message and returns its result. diff --git a/examples/lang-err-integration-tests/call-builder/lib.rs b/examples/lang-err-integration-tests/call-builder/lib.rs index fccfff0c43..547b759e32 100755 --- a/examples/lang-err-integration-tests/call-builder/lib.rs +++ b/examples/lang-err-integration-tests/call-builder/lib.rs @@ -62,7 +62,7 @@ mod call_builder { code_hash: Hash, selector: [u8; 4], init_value: bool, - ) -> Option { + ) -> Option<::ink::LangError> { use ink::env::{ call::{ build_create, @@ -74,19 +74,30 @@ mod call_builder { let result = build_create::< DefaultEnvironment, - constructors_return_value::ConstructorsReturnValueRef, + _, + // constructors_return_value::ConstructorsReturnValueRef, >() .code_hash(code_hash) .gas_limit(0) .endowment(0) .exec_input(ExecutionInput::new(Selector::new(selector)).push_arg(init_value)) .salt_bytes(&[0xDE, 0xAD, 0xBE, 0xEF]) + .returns::>() .params() - .instantiate(); + .instantiate() + .expect("Error from the Contracts pallet."); + ::ink::env::debug_println!("Result from `instantiate` {:?}", &result); - // NOTE: Right now we can't handle any `LangError` from `instantiate`, we can only tell - // that our contract reverted (i.e we see error from the Contracts pallet). - result.ok().map(|id| ink::ToAccountId::to_account_id(&id)) + match result { + Ok(_) => None, + Err(e @ ink::LangError::CouldNotReadInput) => Some(e), + Err(_) => { + unimplemented!("No other `LangError` variants exist at the moment.") + } + } } } @@ -210,14 +221,8 @@ mod call_builder { None, ) .await - .expect("Client failed to call `call_builder::call_instantiate`.") - .value - .expect("Dispatching `call_builder::call_instantiate` failed."); - - assert!( - call_result.is_some(), - "Call using valid selector failed, when it should've succeeded." - ); + .expect("Calling `call_builder::call_instantiate` failed"); + dbg!(&call_result.value); Ok(()) } @@ -259,14 +264,8 @@ mod call_builder { None, ) .await - .expect("Client failed to call `call_builder::call_instantiate`.") - .value - .expect("Dispatching `call_builder::call_instantiate` failed."); - - assert!( - call_result.is_none(), - "Call using invalid selector succeeded, when it should've failed." - ); + .expect("Client failed to call `call_builder::call_instantiate`."); + dbg!(&call_result.value); Ok(()) }