2

I have a Smart Contract "MyCoin". It has another SmartContract "Dex" as dependency.

MyCoin:

import "./openzeppelin/contracts/token/ERC721/IERC721.sol"; //
import "./openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "./openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "./openzeppelin/contracts/utils/Address.sol";
import "./openzeppelin/contracts/utils/Context.sol";
import "./openzeppelin/contracts/utils/Strings.sol";
import "./openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./openzeppelin/contracts/access/Ownable.sol";
import "./Dex.sol";


contract MyCoin is ERC721Holder, ERC165, IERC721Metadata, Ownable{


using Address for address;
using String
s for uint256;

Dex:

    pragma solidity ^0.8.0;
    
    import "./openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
    import "./openzeppelin/contracts/security/ReentrancyGuard.sol";
    import "./MyCoin.sol";
    
    contract DEX is ERC721Holder, ReentrancyGuard{
        MyCoin coin;
        uint256 private _basis;

Code to compile with solc:

const path = require("path");
      const fs = require("fs-extra");
      const solc = require("solc");

      const MyCoin = fs.readFileSync(path.resolve(__dirname, "../contracts", "MyCoin.sol"), "utf8");

      const IERC721 = fs.readFileSync(path.resolve(__dirname, "../contracts/openzeppelin/contracts/token/ERC721", "IERC721.sol"), "utf8");
      const IERC721Receiver = fs.readFileSync(path.resolve(__dirname, "../contracts/openzeppelin/contracts/token/ERC721", "IERC721Receiver.sol"), "utf8");
      const ERC721Holder = fs.readFileSync(path.resolve(__dirname,"../contracts/openzeppelin/contracts/token/ERC721/utils","ERC721Holder.sol"), "utf8");
      const IERC721Metadata = fs.readFileSync(path.resolve(__dirname,"../contracts/openzeppelin/contracts/token/ERC721/extensions","IERC721Metadata.sol"), "utf8");
      const Address = fs.readFileSync(path.resolve(__dirname,"../contracts/openzeppelin/contracts/utils","Address.sol"), "utf8");
      const Context = fs.readFileSync(path.resolve(__dirname,"../contracts/openzeppelin/contracts/utils","Context.sol"), "utf8");
      const Strings = fs.readFileSync(path.resolve(__dirname,"../contracts/openzeppelin/contracts/utils","Strings.sol"), "utf8");
      const ERC165 = fs.readFileSync(path.resolve(__dirname,"../contracts/openzeppelin/contracts/utils/introspection","ERC165.sol"), "utf8");
      const Ownable = fs.readFileSync(path.resolve(__dirname,"../contracts/openzeppelin/contracts/access","Ownable.sol"), "utf8");
      const Dex = fs.readFileSync(path.resolve(__dirname,"../contracts","Dex.sol"));
      const ReentrancyGuard = fs.readFileSync(path.resolve(__dirname, "../contracts/openzeppelin/contracts/security","ReentrancyGuard.sol"), "utf8");
      const IERC165 = fs.readFileSync(path.resolve(__dirname, "../contracts/openzeppelin/contracts/utils/introspection","IERC165.sol"), "utf8");

      const buildPath = path.resolve(__dirname, "../build");
      fs.removeSync(buildPath);

      function compileContract(Contract) {
        const contractPath = path.resolve(...Contract);  
        
        const contractSourceCode = fs.readFileSync(contractPath, "utf8");
        
        fs.ensureDirSync(buildPath);
        
        var input = {
            language: "Solidity",
            sources: {
              Contract: {
                content: contractSourceCode
              }
            },
            settings: {
                optimizer: {
                    enabled: true
                },
                outputSelection: {
                    "*": {
                        "*": [ "*" ]
                    }
                }
            }
        };
    
        function findImports(lpath) {

            if (lpath === "openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol") return { contents: `${IERC721Metadata}` };
            if (lpath === "openzeppelin/contracts/token/ERC721/IERC721Receiver.sol") return {contents: `${IERC721Receiver}`};
            if (lpath === "openzeppelin/contracts/token/ERC721/IERC721.sol") return { contents: `${IERC721}` };
            if (lpath === "openzeppelin/contracts/security/ReentrancyGuard.sol") return { contents: `${ReentrancyGuard}` };
            if (lpath === "openzeppelin/contracts/utils/Address.sol") return { contents: `${Address}` };
            if (lpath === "openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol") return { contents: `${ERC721Holder}` };
            if (lpath === "openzeppelin/contracts/utils/Context.sol") return { contents: `${Context}` };
            if (lpath === "openzeppelin/contracts/utils/Strings.sol") return { contents: `${Strings}` };
            if (lpath === "openzeppelin/contracts/utils/introspection/ERC165.sol") return { contents: `${ERC165}` };
            if (lpath === "Dex.sol") return { contents: `${Dex}` };
            if (lpath === "MyCoin.sol") return { contents: `${MyCoin}` };
            if (lpath === "openzeppelin/contracts/access/Ownable.sol") return { contents: `${Ownable}` };
            if (lpath === "openzeppelin/contracts/utils/introspection/IERC165.sol") return {contents: `${IERC165}`};
            else {
              res.send(lpath);
              return {};
            }
          }
    
        output = JSON.parse(solc.compile(JSON.stringify(input), { import: findImports }));
        res.send(output);
        //for(var contractName in output.contracts.Contract) {
        //    fs.outputJsonSync(
        //       path.resolve(buildPath, `${contractName}.json`),
        //        output.contracts.Contract[contractName]
        //    );
        //}    
    }

    compileContract([__dirname,"../contracts/", "MyCoin.sol"]);

    res.send(output);

Error:

{"errors":[{"component":"general","errorCode":"2333","formattedMessage":"DeclarationError: Identifier already declared.\n  --> Contract:16:1:\n   |\n16 | contract MyCoin is ERC721Holder, ERC165, IERC721Metadata, Ownable{\n   | ^ (Relevant source part starts here and spans across multiple lines).\nNote: The previous declaration is here:\n  --> Contract:13:1:\n   |\n13 | import \"./Dex.sol\";\n   | ^^^^^^^^^^^^^^^^^^^\n\n","message":"Identifier already declared.","secondarySourceLocations":[{"end":670,"file":"Contract","message":"The previous declaration is here:","start":651}],"severity":"error","sourceLocation":{"end":19560,"file":"Contract","start":676},"type":"DeclarationError"}],"sources":{"Contract":{"id":0},"Dex.sol":{"id":1},"MyCoin.sol":{"id":2},"openzeppelin/contracts/access/Ownable.sol":{"id":3},"openzeppelin/contracts/security/ReentrancyGuard.sol":{"id":4},"openzeppelin/contracts/token/ERC721/IERC721.sol":{"id":5},"openzeppelin/contracts/token/ERC721/IERC721Receiver.sol":{"id":6},"openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol":{"id":7},"openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol":{"id":8},"openzeppelin/contracts/utils/Address.sol":{"id":9},"openzeppelin/contracts/utils/Context.sol":{"id":10},"openzeppelin/contracts/utils/Strings.sol":{"id":11},"openzeppelin/contracts/utils/introspection/ERC165.sol":{"id":12},"openzeppelin/contracts/utils/introspection/IERC165.sol":{"id":13}}}

When I just compile for example Reentrancyguard, it has no problem. So I believe it has to do with the imports having the same name. When I delete the imports in one File that error doesn't show up anymore, but the error that certain datatypes can not be identified (because of the import missing). Thanks for your help!

1 Answer 1

1

Your problem is that Dex.sol imports "./MyCoin.sol" and MyCoin.sol imports "./Dex.sol".

The way compileContract(..) works it will include two copies of "MyCoin" when compiling MyCoin.sol.

I'd try to avoid that circular dependency. One possible way to do that is to use interfaces.

For example if Dex use MyCoin as an ERC721 then you can skip importing ./MyCoin.sol from Dex.sol.

If that doesn't work you can create your own interface IMyCoin declaring public methods from MyCoin.

1
  • Late answer, but that’s exactly how I resolved my issue back then. Thanks for your reply and clearing up, marking the comment as solution!
    – Luex
    Commented Jan 3, 2023 at 2:17

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.