Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

abigen: ambiguous import of EthCall for inheriting contracts #867

Closed
sveitser opened this issue Feb 5, 2022 · 7 comments
Closed

abigen: ambiguous import of EthCall for inheriting contracts #867

sveitser opened this issue Feb 5, 2022 · 7 comments
Labels
bug Something isn't working

Comments

@sveitser
Copy link
Contributor

sveitser commented Feb 5, 2022

Version

├── ethers v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   ├── ethers-addressbook v0.1.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   ├── ethers-contract v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   ├── ethers-contract-abigen v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-contract-derive v0.6.0 (proc-macro) (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   │   ├── ethers-contract-abigen v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   │   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-providers v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   ├── ethers-etherscan v0.2.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-solc v0.2.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   ├── ethers-middleware v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   ├── ethers-contract v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-etherscan v0.2.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-providers v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   │   ├── ethers-signers v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc)
│   │   │   ├── ethers-core v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   ├── ethers-providers v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   ├── ethers-signers v0.6.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)
│   └── ethers-solc v0.2.0 (https://github.com/gakonst/ethers-rs#b2b891dc) (*)

Platform
Linux bix 5.10.90 #1-NixOS SMP Wed Jan 5 11:40:34 UTC 2022 x86_64 GNU/Linux

Description
When a contract inherits from another contract the abigen macro generates one EthCall for each function call (with the same name for each contract) and then imports all of them to the top-level. Trying to use ...Call then leads to

error[E0659]: `FunCall` is ambiguous (glob import vs glob import in the same module)

My use case is FunCall::decode(tx.input) for decoding calldata.

To reproduce one can use

abigen!(
    Foo,
    r#"[fun()]"#;
    Bar,
    r#"[fun()]"#;
);

and expand the macro or just refer to FunCall in code after calling the abigen macro.

Expanded macro:

pub mod __shared_types {}
pub use foo_mod::*;
#[allow(clippy::too_many_arguments)]
mod foo_mod {
    #![allow(clippy::enum_variant_names)]
    #![allow(dead_code)]
    #![allow(clippy::type_complexity)]
    #![allow(unused_imports)]
    use ethers_contract::{
        builders::{ContractCall, Event},
        Contract, Lazy,
    };
    use ethers_core::{
        abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable},
        types::*,
    };
    use ethers_providers::Middleware;
    #[doc = "Foo was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"]
    use std::sync::Arc;
    pub static FOO_ABI: ethers_contract::Lazy<ethers_core::abi::Abi> =
        ethers_contract::Lazy::new(|| {
            ethers_core::abi::parse_abi_str("[fun()]").expect("invalid abi")
        });
    #[derive(Clone)]
    pub struct Foo<M>(ethers_contract::Contract<M>);

    impl<M> std::ops::Deref for Foo<M> {
        type Target = ethers_contract::Contract<M>;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<M: ethers_providers::Middleware> std::fmt::Debug for Foo<M> {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            f.debug_tuple("Foo").field(&self.address()).finish()
        }
    }
    impl<'a, M: ethers_providers::Middleware> Foo<M> {
        #[doc = r" Creates a new contract instance with the specified `ethers`"]
        #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"]
        #[doc = r" object"]
        pub fn new<T: Into<ethers_core::types::Address>>(
            address: T,
            client: ::std::sync::Arc<M>,
        ) -> Self {
            let contract =
                ethers_contract::Contract::new(address.into(), FOO_ABI.clone(), client);
            Self(contract)
        }
        #[doc = "Calls the contract\'s `fun` (0x946644cd) function"]
        pub fn fun(&self) -> ethers_contract::builders::ContractCall<M, ()> {
            self.0
                .method_hash([148, 102, 68, 205], ())
                .expect("method not found (this should never happen)")
        }
    }
    #[doc = "Container type for all input parameters for the `fun`function with signature `fun()` and selector `[148, 102, 68, 205]`"]
    #[derive(
        Clone,
        Debug,
        Default,
        Eq,
        PartialEq,
        ethers_contract::EthCall,
        ethers_contract::EthDisplay,
    )]
    #[ethcall(name = "fun", abi = "fun()")]
    pub struct FunCall;
}
pub use bar_mod::*;
#[allow(clippy::too_many_arguments)]
mod bar_mod {
    #![allow(clippy::enum_variant_names)]
    #![allow(dead_code)]
    #![allow(clippy::type_complexity)]
    #![allow(unused_imports)]
    use ethers_contract::{
        builders::{ContractCall, Event},
        Contract, Lazy,
    };
    use ethers_core::{
        abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable},
        types::*,
    };
    use ethers_providers::Middleware;
    #[doc = "Bar was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"]
    use std::sync::Arc;
    pub static BAR_ABI: ethers_contract::Lazy<ethers_core::abi::Abi> =
        ethers_contract::Lazy::new(|| {
            ethers_core::abi::parse_abi_str("[fun()]").expect("invalid abi")
        });
    #[derive(Clone)]
    pub struct Bar<M>(ethers_contract::Contract<M>);

    impl<M> std::ops::Deref for Bar<M> {
        type Target = ethers_contract::Contract<M>;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<M: ethers_providers::Middleware> std::fmt::Debug for Bar<M> {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            f.debug_tuple("Bar").field(&self.address()).finish()
        }
    }
    impl<'a, M: ethers_providers::Middleware> Bar<M> {
        #[doc = r" Creates a new contract instance with the specified `ethers`"]
        #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"]
        #[doc = r" object"]
        pub fn new<T: Into<ethers_core::types::Address>>(
            address: T,
            client: ::std::sync::Arc<M>,
        ) -> Self {
            let contract =
                ethers_contract::Contract::new(address.into(), BAR_ABI.clone(), client);
            Self(contract)
        }
        #[doc = "Calls the contract\'s `fun` (0x946644cd) function"]
        pub fn fun(&self) -> ethers_contract::builders::ContractCall<M, ()> {
            self.0
                .method_hash([148, 102, 68, 205], ())
                .expect("method not found (this should never happen)")
        }
    }
    #[doc = "Container type for all input parameters for the `fun`function with signature `fun()` and selector `[148, 102, 68, 205]`"]
    #[derive(
        Clone,
        Debug,
        Default,
        Eq,
        PartialEq,
        ethers_contract::EthCall,
        ethers_contract::EthDisplay,
    )]
    #[ethcall(name = "fun", abi = "fun()")]
    pub struct FunCall;
}
@sveitser sveitser added the bug Something isn't working label Feb 5, 2022
@mattsse
Copy link
Collaborator

mattsse commented Feb 5, 2022

ah I see,
this probably won't happen if you use the abigen! macro twice instead of bundling them together

@sveitser
Copy link
Contributor Author

sveitser commented Feb 5, 2022

I thought it's recommended to bundle them all together to take advantage of the type de-duplication.

@mattsse
Copy link
Collaborator

mattsse commented Feb 5, 2022

this only provides a benefit if both contracts use the same custom struct types, which are then shared for all contracts, as you can see in your example the __shared_types module is empty.

perhaps this is ambiguous in the docs

@mattsse
Copy link
Collaborator

mattsse commented Feb 5, 2022

we don't check if there are calls that are the same

@sveitser
Copy link
Contributor Author

sveitser commented Feb 5, 2022

Ok. I usually need the de-duplication feature. Could the mod foo_mod be made pub instead so that one could import it from there?

@mattsse
Copy link
Collaborator

mattsse commented Feb 5, 2022

the choice to reexport was made to use the types in the same scope the macro is used but I think we could make it public.

as a workaround you can do this

mod foo {
   abigen!(foo...)
}
mod bar {
   abigen!(bar...)
}

@gakonst
Copy link
Owner

gakonst commented May 31, 2022

should we close this now that #1332 is merged?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants