Summary
I am using an Ink! smart contract (implemented in contract.rs) code calling a chain extension method.
This works well.
However, I want to split my code and call the extension method in a new module (let's call it util.rs).
What is the idiomatic way to share the same env with this module. In other words I want to be able to call self.env().extension.my_method from utils.rs method.
Update
I will ask my question in a more concise and concrete way, suppose the following code in a ink! smart contract:
use crate::CustomEnvironment;
// use ink_env::chain_extension::ChainExtension; NOT EXPOSED PUBLICLY
// Suppose we want to define this method that takes the extension as parameter
fn call_a_method_extension(ext: <<CustomEnvironment>::ChainExtension as ChainExtensionInstance>::Instance) {
// use ext here
// ext.call_on_chain_method
}
// ...
let ext = Self::env().extension();
// Info from rust-analyser:
// ChainExtensionInstance<Self = Environment<Self = E>::ChainExtension>::Instance
// <<E as Environment>::ChainExtension as ChainExtensionInstance>::Instance
// we want to pass ext to call_a_method_extension
call_a_method_extension(ext);
// ...
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum CustomEnvironment {}
impl Environment for CustomEnvironment {
const MAX_EVENT_TOPICS: usize = <ink_env::DefaultEnvironment as Environment>::MAX_EVENT_TOPICS;
type AccountId = <ink_env::DefaultEnvironment as Environment>::AccountId;
type Balance = <ink_env::DefaultEnvironment as Environment>::Balance;
type Hash = <ink_env::DefaultEnvironment as Environment>::Hash;
type BlockNumber = <ink_env::DefaultEnvironment as Environment>::BlockNumber;
type Timestamp = <ink_env::DefaultEnvironment as Environment>::Timestamp;
type ChainExtension = ConcreteOps;
}
What type need to be written to the ext parameter in call_a_method_extension method ?
Archive
First attempt
I try to overlad the + operation with a basic functions for now.
Share the EnvAccess to a struct defined in util.rs
// utils.rs
use crate::CustomEnvironment;
use ink_lang::EnvAccess;
#[derive(Debug)]
pub struct VeryUtil<'a> {
pub value: ink_prelude::vec::Vec<u8>,
pub extension: EnvAccess<'a, CustomEnvironment>,
}
impl<'a> VeryUtil<'a> {
pub fn new(
value: ink_prelude::vec::Vec<u8>,
extension: EnvAccess<'a, CustomEnvironment>,
) -> Self {
VeryUtil { value, extension }
}
}
impl core::ops::Add<VeryUtil<'_>> for VeryUtil<'_> {
// For the next line I get
// generic associated types are unstable
// type Output<'a> = VeryUtil<'a>;
// for now I tested with
type Output = Vec<u8>;
fn add(self, rhs: VeryUtil) -> Vec<u8> {
println!("> add is called");
let val = self
.extension
.extension()
.add_values(&self.value, &rhs.value);
val.unwrap()
}
}
Here I get a warning when the output was the same struct, I commented in the code. A subsidiary question is how to avoid to share for each struct the env, but without it I would not be able to call the extension method in the Add overload part!
Use the defined struct in one of the exposed contract methods:
// contract.rs
1 let very_util_val1 = crate::util::VeryUtil::new(my_vec1.clone(), self.env());
2 let very_util_val2 = crate::util::VeryUtil::new(my_vec2.clone(), self.env());
3 // All the code purpose is to be able to do this!!!
4 let result = very_util_val1 + very_util_val2
I get the following error for line 1 and 2 :
cannot borrow `*self` as mutable because it is also borrowed as immutable
My initial choice was to share a __ink_ConreteOpsInstance (self.env().extension) but I did not know how to define this type in my struct.
Another idea
Maybe I can ask access like the contract module with the following macro ...
#[ink::contract(env = crate::CustomEnvironment)]
... but this module is not a contract just a sub module.