I have made a contract in ink! that build fine, and I am trying to make e2e tests. I don't manage to do this even by using the examples in ink! repertory.

My contract is a swap contract: it takes the two contracts address, and allow two users to exchange their tokens.

Below is the beginning of my contract:

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), no_main)]

mod token_swap {
    use ink::storage::Mapping;
    use ink::LangError;
    use ink_env::call::{build_call, ExecutionInput, Selector};
    use ink_env::DefaultEnvironment;

    pub type Swap = (
        AccountId,         // creator
        AccountId,         // token_a
        AccountId,         // token_b
        Balance,           // amount_a
        Balance,           // amount_b

    #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
    #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
    pub enum Error {

    pub type Result<T> = core::result::Result<T, Error>;

    pub struct TokenSwap {
        pub swaps: Mapping<u64, Swap>,
        pub swap_count: u64,


    pub struct SwapCreated {
        id: u64,
        creator: AccountId,

    pub struct SwapAccepted {
        id: u64,
        acceptor: AccountId,

    pub struct SwapDeleted {
        id: u64,

    impl TokenSwap {
        pub fn new() -> Self {
            Self {
                swaps: Default::default(),
                swap_count: 0,


        fn get_balance(&self, token_contract: AccountId, account: AccountId) -> Result<Balance> {
            let result: core::result::Result<
                core::result::Result<Balance, LangError>,
            > = build_call::<DefaultEnvironment>()

            match result {
                Ok(Ok(balance)) => Ok(balance),
                Ok(Err(_)) => Err(Error::InsufficientBalance),
                Err(_) => Err(Error::CallFailed),

        pub fn create_swap(
            &mut self,
            token_a: AccountId,
            token_b: AccountId,
            amount_a: Balance,
            amount_b: Balance,

        ) -> Result<u64> {

                let caller = self.env().caller();
                let balance_a: Balance = self.get_balance(token_a, caller)?;

                if balance_a < amount_a {
                    return Err(Error::InsufficientBalance);

                let balance_b: Balance = self.get_balance(token_b, caller)?;
                if balance_b < amount_b {
                    return Err(Error::InsufficientBalance);

                self.transfer_token(token_a, caller, self.env().account_id(), amount_a)?;


                let new_swap = (

                self.swaps.insert(self.swap_count, &new_swap);
                let id = self.swap_count;
                self.swap_count = self.swap_count.checked_add(1).ok_or(Error::CallFailed)?;

                self.env().emit_event(SwapCreated {
                    creator: caller,


I want to make e2e tests, so to do that, I wanted to add erc20 contract (from parity) and add it to my cargo toml. I did that, but it does not work, and I don't understand how to do it ...

Here is the Cargo toml of my contract :

ink = { version = "4.2.0", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }
ink_env = { version = "4.2.1", default-features = false }
ink_lang = { version = "3.4.0", default-features = false }

ink_e2e = "4.2.1"
erc20 = { path = "../erc20", default-features = false, features = ["ink-as-dependency"] }

path = "lib.rs"

default = ["std"]
std = [

ink-as-dependency = []
e2e-tests = []

And here is the test :

mod e2e_tests {
    use super::*;
    use erc20::erc20::Erc20;
    use ink_e2e::build_message;

    type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

    #[ink_e2e::test(additional_contracts = "erc20/Cargo.toml ")]
    async fn create_swap_works(mut client: ink_e2e::Client<C, E>) -> E2EResult<()> {
        // Instantiate erc20 contract
        let token_a = Erc20::new(100);
        let token_b = Erc20::new(100);

        let accounts = ink::env::test::default_accounts::<ink::env::DefaultEnvironment>();

            let amount_a = 100u128;
            let amount_b = 100u32;
         let constructor = TokenSwapRef::new_default();
            let contract_acc_id = client
                .instantiate("token_swap", &ink_e2e::bob(), constructor, 0, None)
                .expect("instantiate failed")

            let create_swap = build_message::<TokenSwapRef>(contract_acc_id.clone())
                .call(|token_swap| token_swap.create_swap(token_a, token_b, amount_a, amount_b));
            let create_swap_res = client
                .call(&ink_e2e::bob(), create_swap, 0, None)
                .expect("create_swap failed");


If someone could explain step by step how to achieve it, I would be so grateful, all I tried did not work ...

1 Answer 1


If you using Erc20 contract from the ink! repo, you first need to declare contract module as pub here.

Secondly, you need to use Erc20Ref in order to gain an instance of a constructor like so let mut constructor = Erc20Ref::new(total_supply);

So you import should be use erc20::erc20::{Erc20, Erc20Ref};

Finally, since you message accepts AccountId you need to instantiate your two Erc20 contracts.

let erc20 = client
    .instantiate("erc20", &ink_e2e::alice(), &mut constructor)
    .expect("instantiate failed");

And you can access the address of the instantiated contract with erc20.account_id

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.