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.


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

// ...
#[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 ?


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;

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
            .add_values(&self.value, &rhs.value);


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.

  • 1
    Can you provide a small repo reproducer, so I can play around and see what works? Mar 6, 2023 at 10:53

2 Answers 2


It is currently not possible to reference the chain extension method from a different file.

It's good that you raised this and I just created this issue for it: https://github.com/paritytech/ink/issues/1719.


Have you checked how the module separation is done for the Swanky-node?

  • I will check it, thank you!
    – Castor19
    Sep 2, 2022 at 12:37
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Sep 3, 2022 at 13:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.