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

MultiAbigen does not create rust structs for solidity structs #947

Closed
sveitser opened this issue Feb 22, 2022 · 3 comments · Fixed by #950 or #952
Closed

MultiAbigen does not create rust structs for solidity structs #947

sveitser opened this issue Feb 22, 2022 · 3 comments · Fixed by #950 or #952
Labels
bug Something isn't working

Comments

@sveitser
Copy link
Contributor

Version

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

Platform
Linux bix 5.10.101 #1-NixOS SMP Wed Feb 16 11:54:31 UTC 2022 x86_64 GNU/Linux

Description
Generating bindings for contract

pragma solidity >=0.8.0;
contract Greeter {

    struct Stuff { bool attr; }

    function greet(Stuff memory stuff) public view returns (Stuff memory) {
        return stuff;
    }
}

with the build.rs script:

use std::path::Path;

use ethers_contract_abigen::MultiAbigen;
use ethers_solc::{Project, ProjectPathsConfig};

fn main() {
    // configure the project with all its paths, solc, cache etc.
    let root = Path::new(&env!("CARGO_MANIFEST_DIR"));
    let project = Project::builder()
        .paths(ProjectPathsConfig::hardhat(root).unwrap())
        .build()
        .unwrap();
    let _output = project.compile().unwrap();

    // Tell Cargo that if a source file changes, to rerun this build script.
    project.rerun_if_sources_changed();

    let gen = MultiAbigen::from_json_files(root.join("artifacts")).unwrap();
    let bindings = gen.build().unwrap();
    bindings.write_to_module("src/bindings", true).unwrap();
}

I expect to have a Stuff struct in the rust code. The generated file src/bindings/mod.rs does not contain that. For example Greeter.greet takes stuff: (bool,), as argument.

#![allow(clippy::all)]
//! This module contains abigen! generated bindings for solidity contracts.
//! This is autogenerated code.
//! Do not manually edit these files.
//! This file may be overwritten by the codegen system at any time.
pub use greeter_mod::*;
#[allow(clippy::too_many_arguments)]
mod greeter_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 = "Greeter was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"]
    use std::sync::Arc;
    pub static GREETER_ABI: ethers::contract::Lazy<ethers::core::abi::Abi> =
        ethers::contract::Lazy::new(|| {
            serde_json :: from_str ("[{\"type\":\"function\",\"name\":\"greet\",\"inputs\":[{\"internalType\":\"struct Greeter.Stuff\",\"name\":\"stuff\",\"type\":\"tuple\",\"components\":[{\"type\":\"bool\"}]}],\"outputs\":[{\"internalType\":\"struct Greeter.Stuff\",\"name\":\"\",\"type\":\"tuple\",\"components\":[{\"type\":\"bool\"}]}],\"stateMutability\":\"view\"}]") . expect ("invalid abi")
        });
    #[derive(Clone)]
    pub struct Greeter<M>(ethers::contract::Contract<M>);
    impl<M> std::ops::Deref for Greeter<M> {
        type Target = ethers::contract::Contract<M>;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<M: ethers::providers::Middleware> std::fmt::Debug for Greeter<M> {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            f.debug_tuple(stringify!(Greeter))
                .field(&self.address())
                .finish()
        }
    }
    impl<'a, M: ethers::providers::Middleware> Greeter<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(), GREETER_ABI.clone(), client);
            Self(contract)
        }
        #[doc = "Calls the contract's `greet` (0x5581701b) function"]
        pub fn greet(
            &self,
            stuff: (bool,),
        ) -> ethers::contract::builders::ContractCall<M, (bool,)> {
            self.0
                .method_hash([85, 129, 112, 27], (stuff,))
                .expect("method not found (this should never happen)")
        }
    }
    #[doc = "Container type for all input parameters for the `greet`function with signature `greet((bool))` and selector `[85, 129, 112, 27]`"]
    #[derive(
        Clone,
        Debug,
        Default,
        Eq,
        PartialEq,
        ethers :: contract :: EthCall,
        ethers :: contract :: EthDisplay,
    )]
    #[ethcall(name = "greet", abi = "greet((bool))")]
    pub struct GreetCall {
        pub stuff: (bool,),
    }
}
@sveitser sveitser added the bug Something isn't working label Feb 22, 2022
@mattsse
Copy link
Collaborator

mattsse commented Feb 22, 2022

thanks for this repro!
I have a hunch but will debug to confirm

@sveitser
Copy link
Contributor Author

@mattsse thanks for the quick fix. This works for the repro but I'm still seeing the problem when I try it on a more complex project. Will post here if I have another repro.

@sveitser
Copy link
Contributor Author

Having a nested struct still triggers the problem here

pragma solidity >=0.8.0;

contract Greeter {

    struct Inner {
        bool a;
    }

    struct Stuff {
        Inner inner;
    }

    function greet(Stuff calldata stuff) public view returns (Stuff memory) {
        return stuff;
    }
}

Gives

        pub fn greet(
            &self,
            stuff: ((bool,),),
        ) -> ethers::contract::builders::ContractCall<M, ((bool,),)> { 

Full generated binings:

#![allow(clippy::all)]
//! This module contains abigen! generated bindings for solidity contracts.
//! This is autogenerated code.
//! Do not manually edit these files.
//! This file may be overwritten by the codegen system at any time.
pub use greeter_mod::*;
#[allow(clippy::too_many_arguments)]
mod greeter_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 = "Greeter was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"]
    use std::sync::Arc;
    pub static GREETER_ABI: ethers::contract::Lazy<ethers::core::abi::Abi> =
        ethers::contract::Lazy::new(|| {
            serde_json :: from_str ("[{\"type\":\"function\",\"name\":\"greet\",\"inputs\":[{\"internalType\":\"struct Greeter.Stuff\",\"name\":\"stuff\",\"type\":\"tuple\",\"components\":[{\"type\":\"tuple\",\"components\":[{\"type\":\"bool\"}]}]}],\"outputs\":[{\"internalType\":\"struct Greeter.Stuff\",\"name\":\"\",\"type\":\"tuple\",\"components\":[{\"type\":\"tuple\",\"components\":[{\"type\":\"bool\"}]}]}],\"stateMutability\":\"view\"}]") . expect ("invalid abi")
        });
    #[derive(Clone)]
    pub struct Greeter<M>(ethers::contract::Contract<M>);
    impl<M> std::ops::Deref for Greeter<M> {
        type Target = ethers::contract::Contract<M>;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<M: ethers::providers::Middleware> std::fmt::Debug for Greeter<M> {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            f.debug_tuple(stringify!(Greeter))
                .field(&self.address())
                .finish()
        }
    }
    impl<'a, M: ethers::providers::Middleware> Greeter<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(), GREETER_ABI.clone(), client);
            Self(contract)
        }
        #[doc = "Calls the contract's `greet` (0x8ed3bc56) function"]
        pub fn greet(
            &self,
            stuff: ((bool,),),
        ) -> ethers::contract::builders::ContractCall<M, ((bool,),)> {
            self.0
                .method_hash([142, 211, 188, 86], (stuff,))
                .expect("method not found (this should never happen)")
        }
    }
    #[doc = "Container type for all input parameters for the `greet`function with signature `greet(((bool)))` and selector `[142, 211, 188, 86]`"]
    #[derive(
        Clone,
        Debug,
        Default,
        Eq,
        PartialEq,
        ethers :: contract :: EthCall,
        ethers :: contract :: EthDisplay,
    )]
    #[ethcall(name = "greet", abi = "greet(((bool)))")]
    pub struct GreetCall {
        pub stuff: ((bool,),),
    }
}

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
3 participants