Giter Club home page Giter Club logo

Comments (11)

mattsse avatar mattsse commented on July 18, 2024 1

fyi @Evalir

from ethers-rs.

mattsse avatar mattsse commented on July 18, 2024 1

@Evalir was looking into this but no fix yet, sharing some context:

    "sources": {
      "lib/solady/ext/woke/ERC20Mock.sol": {
        "keccak256": "0x508149a04ca17da422e50df1d25fcc5dd88ef666398eeca6800686a6987f95ff",
        "urls": [
          "bzz-raw://30e858817901565516da9416fb800c3f64cc3dc95b38736ef008248e4b71891c",
          "dweb:/ipfs/QmcKh4wdg7Gy5QWawJavG694W3RjLmmaifALFFZyu6adGp"
        ],
        "license": "MIT"
      },
      "src/tokens/ERC20.sol": {
        "keccak256": "0x264e4675697d05dfb9bbe9cc91c6bda7962d934f1e940336fd75d509b7f396c4",
        "urls": [
          "bzz-raw://5856338689f03f36c057203c5085243e104b8487274432062ebf076b512edeea",
          "dweb:/ipfs/QmXrqgaWQikKkHfoBkYPxeMTJWUY5uf7kSmipNbpU35XwK"
        ],
        "license": "MIT"
      },
      "src/utils/SafeTransferLib.sol": {
        "keccak256": "0x64af21dfdc2042a9dc0c6e970072523f11c934e14aba05696b17e8f736d2a70e",
        "urls": [
          "bzz-raw://4f9ffeb99b644857294b1535ad3d952ee705237d4208e48e18f54a20818aa09c",
          "dweb:/ipfs/QmQKmo7qqxUsyivySvbvSe3cgyvJRAqztejcdgGEWRCddx"
        ],
        "license": "MIT"
      }

see lib/solady/ext/woke/ERC20Mock.sol? That’s passed in correctly, since it’s an import coming from an user test file, not a library file

src/tokens/ERC20.sol and the SafeTransferLib imports are coming from solady itself. ERC20Mock imports both of these so we get these import_paths, but there’s no post-processing of these once we know they’re coming from a library

so the issue is, “internal” library import paths are passed in to solc without appending the library they correspond to to the path

(“internal” library import = any internal file that solady imports inside a contract)

I think the fix here might just be to canonicalize every import path we pass

@plotchy

you can check out both repos, then uncomment this in foundry, so it uses your local ethers and compile forge locally, I recommend compiling in debug mode cargo build --bin forge which reasonably fast

https://github.com/foundry-rs/foundry/blob/87283bc9f5657eed126ecb2d2370a471ff409bb7/Cargo.toml#L170-L180

I think the bug is somewhere here:

/// Attempts to resolve an `import` from the given working directory.
///
/// The `cwd` path is the parent dir of the file that includes the `import`
pub fn resolve_import(&self, cwd: &Path, import: &Path) -> Result<PathBuf> {
self.resolve_import_and_include_paths(cwd, import, &mut Default::default())
}

pub fn resolve_library_import(&self, cwd: &Path, import: &Path) -> Option<PathBuf> {

utils::resolve_library(&self.libraries, import)

from ethers-rs.

mattsse avatar mattsse commented on July 18, 2024

ethers-solc are not consistently converting import paths into absolute paths with the root of the project resolved.

if this is about the absolutePath json field, I'm pretty sure that we never touch that since this is solc output

But I think you found the buggy code already.

Looking at:

    "sources": {
      "lib/solady/ext/woke/ERC20Mock.sol": {
        "keccak256": "0x508149a04ca17da422e50df1d25fcc5dd88ef666398eeca6800686a6987f95ff",
        "urls": [
          "bzz-raw://30e858817901565516da9416fb800c3f64cc3dc95b38736ef008248e4b71891c",
          "dweb:/ipfs/QmcKh4wdg7Gy5QWawJavG694W3RjLmmaifALFFZyu6adGp"
        ],
        "license": "MIT"
      },
      "src/tokens/ERC20.sol": {
        "keccak256": "0x264e4675697d05dfb9bbe9cc91c6bda7962d934f1e940336fd75d509b7f396c4",
        "urls": [
          "bzz-raw://5856338689f03f36c057203c5085243e104b8487274432062ebf076b512edeea",
          "dweb:/ipfs/QmXrqgaWQikKkHfoBkYPxeMTJWUY5uf7kSmipNbpU35XwK"
        ],
        "license": "MIT"
      },
      "src/utils/SafeTransferLib.sol": {
        "keccak256": "0x64af21dfdc2042a9dc0c6e970072523f11c934e14aba05696b17e8f736d2a70e",
        "urls": [
          "bzz-raw://4f9ffeb99b644857294b1535ad3d952ee705237d4208e48e18f54a20818aa09c",
          "dweb:/ipfs/QmQKmo7qqxUsyivySvbvSe3cgyvJRAqztejcdgGEWRCddx"
        ],
        "license": "MIT"
      }

for some reason the relative path from project dir to solady lib/solady is stripped from the path. But this is only the case for src, not ext.

need to debug what's going on here.

thanks for this.

from ethers-rs.

0xalpharush avatar 0xalpharush commented on July 18, 2024

Yeah, I think the root cause is related to the path prefix being stripped in the sources which I believe ultimately affects solc's absolutePath

from ethers-rs.

plotchy avatar plotchy commented on July 18, 2024

Ive recently been messing with ethers_solc, remappings, paths and also am familiar enough with slither. I wouldn't mind giving this fix a try.

A question for @mattsse, @DaniPopes and @Evalir. since this includes foundry and ethers, what's the easiest way to iterate on a fix?
Build foundry from source, and change all the Cargo.toml's within to have the ethers dependency point to a local ethers path?

from ethers-rs.

plotchy avatar plotchy commented on July 18, 2024

Thanks for the tips @mattsse. I built the debug bin as you said and then symlinked the bin to forge2 on my PATH and that worked great.

Started digging into this. I have a feeling that ethers is handling this correctly.

I looked through the resolve_* functions and was finding that the imports all looked solid with absolute paths. I ended up chasing this down to see what we provide to solc, and even these objects look good to me.

Here is CompilerInput for alpharush's repro (i minified the contract code to be readable):

[ethers-rs/ethers-solc/src/compile/project.rs:555] &input = CompilerInput {
    language: "Solidity",
    sources: {
        "lib/solady/ext/woke/ERC20Mock.sol": Source {
            content: "pragma solidity ^0.8.4;\nimport \"src/tokens/ERC20.sol\";\ncontract ERC20Mock is ERC20 {}",
        },
        "lib/solady/src/tokens/ERC20.sol": Source {
            content: "pragma solidity ^0.8.4;\nabstract contract ERC20 {}",
        },
        "src/Counter.sol": Source {
            content: "pragma solidity 0.8.13;\nimport \"lib/solady/src/tokens/ERC20.sol\";\ncontract Counter {}",
        },
        "test/Counter.t.sol": Source {
            content: "pragma solidity 0.8.13;\nimport {Counter} from \"../src/Counter.sol\";\nimport {ERC20Mock} from \"lib/solady/ext/woke/ERC20Mock.sol\";\ncontract CounterTest {}",
        },
    },
    settings: Settings {
        remappings: [
            Remapping {
                context: None,
                name: "ds-test/",
                path: "lib/forge-std/lib/ds-test/src",
            },
            Remapping {
                context: None,
                name: "forge-std/",
                path: "lib/forge-std/src",
            },
            Remapping {
                context: None,
                name: "solady/",
                path: "lib/solady",
            },
        ],
        ...,
        libraries: Libraries {
            libs: {},
        },
    },
}

Notice that all these paths are absolute from the root of the repo.

Then i followed this object to see what the actual solc command is:

[ethers-rs/ethers-solc/src/compile/mod.rs:579] &cmd = Command {
    program: "/Users/plotchy/.svm/0.8.13/solc-0.8.13",
    args: [
        "/Users/plotchy/.svm/0.8.13/solc-0.8.13",
        "--base-path",
        "/Users/plotchy/code/learning/ethers-issue-2609",
    ],
    cwd: Some(
        "/Users/plotchy/code/learning/ethers-issue-2609",
    ),
}
[ethers-rs/ethers-solc/src/compile/mod.rs:579] &self.args = [
    "--allow-paths",
    "/Users/plotchy/code/learning/ethers-issue-2609,/Users/plotchy/code/learning/ethers-issue-2609/lib",
    "--include-path",
    "/Users/plotchy/code/learning/ethers-issue-2609/lib/solady",
]

This is what i'd expect again. From here, we add on --standard-json and write to stdin with that CompilerInput object above.

the full command is something like:
/Users/plotchy/.svm/0.8.13/solc-0.8.13 --base-path /Users/plotchy/code/learning/ethers-issue-2609 --allow-paths /Users/plotchy/code/learning/ethers-issue-2609,/Users/plotchy/code/learning/ethers-issue-2609/lib --standard-json <stdin CompilerInput>

Leaving these breadcrumbs here if anyone sees something out of place. Do we know what solc command hardhat uses?

from ethers-rs.

mattsse avatar mattsse commented on July 18, 2024

thanks for this!

hmm, it maybe there's something wrong with postprocessing of the compileroutput then

you can run with env var ETHERS_SOLC_LOG=in=in.json,out=out.json forge ... to get the raw compiler in/out json as files

from ethers-rs.

plotchy avatar plotchy commented on July 18, 2024

Ok, here are the jsons for in and out. I pruned the out.json in this post to contain relevant portions.

full jsons are here:
https://gist.github.com/plotchy/f09b4e92d7fbb9379c20ee6fd351559a

in.json has all absolute paths.

out.json's main points of contention are that the ast for "lib/solady/ext/woke/ERC20Mock.sol" has an ImportDirective with "absolutePath": "src/tokens/ERC20.sol". solc then appends "src/tokens/ERC20.sol" to both the list of sources and the list of contracts. I'm not sure why!

Knowing that in.json has all absolute paths for the sources, I'm not sure how ethers could provide the input differently. As far as I can tell, postprocessing for build info doesnt touch the output ast absolutePaths. There could be an opportunity to touch them up for sure. Does hardhat do that? Or do they provide the input differently?

in.json

{
  "language": "Solidity",
  "sources": {
    "lib/solady/ext/woke/ERC20Mock.sol": {
      "content": "pragma solidity ^0.8.4;\nimport \"src/tokens/ERC20.sol\";\ncontract ERC20Mock is ERC20 {}"
    },
    "lib/solady/src/tokens/ERC20.sol": {
      "content": "pragma solidity ^0.8.4;\nabstract contract ERC20 {}"
    },
    "src/Counter.sol": {
      "content": "pragma solidity 0.8.13;\nimport \"lib/solady/src/tokens/ERC20.sol\";\ncontract Counter {}"
    },
    "test/Counter.t.sol": {
      "content": "pragma solidity 0.8.13;\nimport {Counter} from \"../src/Counter.sol\";\nimport {ERC20Mock} from \"lib/solady/ext/woke/ERC20Mock.sol\";\ncontract CounterTest {}"
    }
  },
  "settings": {
    "remappings": [
      "ds-test/=lib/forge-std/lib/ds-test/src/",
      "forge-std/=lib/forge-std/src/",
      "solady/=lib/solady/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs"
    },
    "outputSelection": {
      "*": {
        "": [
          "ast"
        ],
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata"
        ]
      }
    },
    "evmVersion": "london",
    "libraries": {}
  }
}

out.json

{
  "sources": {
    "lib/solady/ext/woke/ERC20Mock.sol": {
      "id": 0,
      "ast": {
        "absolutePath": "lib/solady/ext/woke/ERC20Mock.sol",
        "id": 6,
        "exportedSymbols": {
          "ERC20": [
            22
          ],
          "ERC20Mock": [
            5
          ]
        },
        "nodeType": "SourceUnit",
        "src": "0:85:0",
        "nodes": [
          {
            "id": 2,
            "nodeType": "ImportDirective",
            "src": "24:30:0",
            "nodes": [],
            "absolutePath": "src/tokens/ERC20.sol",
            "file": "src/tokens/ERC20.sol",
            "nameLocation": "-1:-1:-1",
            "scope": 6,
            "sourceUnit": 23,
            "symbolAliases": [],
            "unitAlias": ""
          }
        ]
      }
    },
    "lib/solady/src/tokens/ERC20.sol": {
      "id": 1,
      "ast": {
        "absolutePath": "lib/solady/src/tokens/ERC20.sol",
      }
    },
    "src/Counter.sol": {
      "id": 2,
      "ast": {
        "absolutePath": "src/Counter.sol",
        "id": 13,
        "exportedSymbols": {
          "Counter": [
            12
          ],
          "ERC20": [
            8
          ]
        },
        "nodeType": "SourceUnit",
        "src": "0:85:2",
        "nodes": [
          {
            "id": 11,
            "nodeType": "ImportDirective",
            "src": "24:41:2",
            "nodes": [],
            "absolutePath": "lib/solady/src/tokens/ERC20.sol",
            "file": "lib/solady/src/tokens/ERC20.sol",
            "nameLocation": "-1:-1:-1",
            "scope": 13,
            "sourceUnit": 9,
            "symbolAliases": [],
            "unitAlias": ""
          }
        ]
      }
    },
    "src/tokens/ERC20.sol": {
      "id": 3,
      "ast": {
        "absolutePath": "src/tokens/ERC20.sol",
        "id": 23,
      }
    },
    "test/Counter.t.sol": {}
  },
  "contracts": {
    "lib/solady/ext/woke/ERC20Mock.sol": {},
    "lib/solady/src/tokens/ERC20.sol": {},
    "src/Counter.sol": {},
    "src/tokens/ERC20.sol": {},
    "test/Counter.t.sol": {}
  }
}

from ethers-rs.

plotchy avatar plotchy commented on July 18, 2024

Since solc appends "src/tokens/ERC20.sol" to sources&contracts and uses that relative path as the key, now I was curious, and copied/renamed the solady lib as solmate. Then I imported another ERC20Mock into the Counter test file so that there would be two imports of the same relative path (colliding key).

Counter.t.sol

pragma solidity 0.8.13;
import {Counter} from "../src/Counter.sol";

// these both import "src/tokens/ERC20.sol"
import {ERC20Mock} from "lib/solady/ext/woke/ERC20Mock.sol"; 
import {ERC20Mock2} from "lib/solmate/ext/woke/ERC20Mock.sol";

contract CounterTest {}

Now the compiler run fails.

Error: 
Compiler run failed:
Error (6275): Source "src/tokens/ERC20.sol" not found: Ambiguous import. Multiple matching files found inside base path and/or include paths: "/Users/plotchy/code/learning/ethers-issue-2609/lib/solady/src/tokens/ERC20.sol", "/Users/plotchy/code/learning/ethers-issue-2609/lib/solmate/src/tokens/ERC20.sol".
 --> lib/solady/ext/woke/ERC20Mock.sol:2:1:
  |
2 | import "src/tokens/ERC20.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Error (6275): Source "src/tokens/ERC20.sol" not found: Ambiguous import. Multiple matching files found inside base path and/or include paths: "/Users/plotchy/code/learning/ethers-issue-2609/lib/solady/src/tokens/ERC20.sol", "/Users/plotchy/code/learning/ethers-issue-2609/lib/solmate/src/tokens/ERC20.sol".
 --> lib/solmate/ext/woke/ERC20Mock.sol:2:1:
  |
2 | import "src/tokens/ERC20.sol";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I dont quite know how to digest all this info. If there is a way for ethers to help make the sources more unambiguous then we should we do that. From what I see in the input commands, we are already doing this as best we can. Postprocessing adjustments don't seem to fix this compiler issue with multiple libs colliding on names.

from ethers-rs.

plotchy avatar plotchy commented on July 18, 2024

@0xalpharush do you have a hardhat repro that complies with your needs that I could take a look at? Their docs do mention some special preprocess and postprocess steps.

Hardhat optimizes compilation by compiling the smallest possible set of files at a time. Files that are compiled together have the same solc input and output. Since having this in each debug file would be meaningfully wasteful, this information is deduplicated in build info files that are placed in artifacts/build-info

from ethers-rs.

0xalpharush avatar 0xalpharush commented on July 18, 2024

Thanks for taking this on and thorough investigation @plotchy. I realize now hardhat works because it doesn't seem to include the test/ directory in the original project I opened this for.

It looks like we can use the remapping context feature to translate imports in dependencies to be relative to the root of the project. For example, import src/tokens/ERC20.sol in root/lib/solady can be translated to lib/solady/src/tokens/ERC20.sol by adding "lib/solady/:src/=lib/solady/src/" to the remappings object of the standard input. (Maybe related to foundry-rs/foundry#5397 and foundry-rs/foundry#5532)

in.json

{
    "language": "Solidity",
    "sources": {
      "lib/solady/ext/woke/ERC20Mock.sol": {
        "content": "pragma solidity ^0.8.4;\nimport \"src/tokens/ERC20.sol\";\ncontract ERC20Mock is ERC20 {}"
      },
      "lib/solady/src/tokens/ERC20.sol": {
        "content": "pragma solidity ^0.8.4;\nabstract contract ERC20 {}"
      },
      "src/Counter.sol": {
        "content": "pragma solidity 0.8.13;\nimport \"lib/solady/src/tokens/ERC20.sol\";\ncontract Counter {}"
      },
      "test/Counter.t.sol": {
        "content": "pragma solidity 0.8.13;\nimport {Counter} from \"../src/Counter.sol\";\nimport {ERC20Mock} from \"lib/solady/ext/woke/ERC20Mock.sol\";\ncontract CounterTest {}"
      }
    },
    "settings": {
      "remappings": [
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/",
        "solady/=lib/solady/",
        "lib/solady/:src/=lib/solady/src/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs"
      },
      "outputSelection": {
        "*": {
          "": [
            "ast"
          ],
          "*": [
            "abi",
            "evm.bytecode",
            "evm.deployedBytecode",
            "evm.methodIdentifiers",
            "metadata"
          ]
        }
      },
      "evmVersion": "london",
      "libraries": {}
    }
  }

out.json

"sources": {
        "lib/solady/ext/woke/ERC20Mock.sol": {
            "ast": {
                "absolutePath": "lib/solady/ext/woke/ERC20Mock.sol",
                "exportedSymbols": {
                    "ERC20": [
                        8
                    ],
                    "ERC20Mock": [
                        5
                    ]
                },
                "id": 6,
                "nodeType": "SourceUnit",
                "nodes": [
                    {
                        "id": 1,
                        "literals": [
                            "solidity",
                            "^",
                            "0.8",
                            ".4"
                        ],
                        "nodeType": "PragmaDirective",
                        "src": "0:23:0"
                    },
                    {
                        "absolutePath": "lib/solady/src/tokens/ERC20.sol",
                        "file": "src/tokens/ERC20.sol",
                        "id": 2,
                        "nameLocation": "-1:-1:-1",
                        "nodeType": "ImportDirective",
                        "scope": 6,
                        "sourceUnit": 9,
                        "src": "24:30:0",
                        "symbolAliases": [],
                        "unitAlias": ""
                    },
                    {
                        "abstract": false,
                        "baseContracts": [
                            {
                                "baseName": {
                                    "id": 3,
                                    "name": "ERC20",
                                    "nodeType": "IdentifierPath",
                                    "referencedDeclaration": 8,
                                    "src": "77:5:0"
                                },
                                "id": 4,
                                "nodeType": "InheritanceSpecifier",
                                "src": "77:5:0"
                            }
                        ],
                        "canonicalName": "ERC20Mock",
                        "contractDependencies": [],
                        "contractKind": "contract",
                        "fullyImplemented": true,
                        "id": 5,
                        "linearizedBaseContracts": [
                            5,
                            8
                        ],
                        "name": "ERC20Mock",
                        "nameLocation": "64:9:0",
                        "nodeType": "ContractDefinition",
                        "nodes": [],
                        "scope": 6,
                        "src": "55:30:0",
                        "usedErrors": []
                    }
                ],
                "src": "0:85:0"
            },
            "id": 0
        },
        "lib/solady/src/tokens/ERC20.sol": {
            "ast": {
                "absolutePath": "lib/solady/src/tokens/ERC20.sol",
                "exportedSymbols": {
                    "ERC20": [
                        8
                    ]
                },
                "id": 9,
                "nodeType": "SourceUnit",
                "nodes": [
                    {
                        "id": 7,
                        "literals": [
                            "solidity",
                            "^",
                            "0.8",
                            ".4"
                        ],
                        "nodeType": "PragmaDirective",
                        "src": "0:23:1"
                    },
                    {
                        "abstract": true,
                        "baseContracts": [],
                        "canonicalName": "ERC20",
                        "contractDependencies": [],
                        "contractKind": "contract",
                        "fullyImplemented": true,
                        "id": 8,
                        "linearizedBaseContracts": [
                            8
                        ],
                        "name": "ERC20",
                        "nameLocation": "42:5:1",
                        "nodeType": "ContractDefinition",
                        "nodes": [],
                        "scope": 9,
                        "src": "24:26:1",
                        "usedErrors": []
                    }
                ],
                "src": "0:50:1"
            },
            "id": 1
        },
        "src/Counter.sol": {
            "ast": {
                "absolutePath": "src/Counter.sol",
                "exportedSymbols": {
                    "Counter": [
                        12
                    ],
                    "ERC20": [
                        8
                    ]
                },
                "id": 13,
                "nodeType": "SourceUnit",
                "nodes": [
                    {
                        "id": 10,
                        "literals": [
                            "solidity",
                            "0.8",
                            ".13"
                        ],
                        "nodeType": "PragmaDirective",
                        "src": "0:23:2"
                    },
                    {
                        "absolutePath": "lib/solady/src/tokens/ERC20.sol",
                        "file": "lib/solady/src/tokens/ERC20.sol",
                        "id": 11,
                        "nameLocation": "-1:-1:-1",
                        "nodeType": "ImportDirective",
                        "scope": 13,
                        "sourceUnit": 9,
                        "src": "24:41:2",
                        "symbolAliases": [],
                        "unitAlias": ""
                    },
                    {
                        "abstract": false,
                        "baseContracts": [],
                        "canonicalName": "Counter",
                        "contractDependencies": [],
                        "contractKind": "contract",
                        "fullyImplemented": true,
                        "id": 12,
                        "linearizedBaseContracts": [
                            12
                        ],
                        "name": "Counter",
                        "nameLocation": "75:7:2",
                        "nodeType": "ContractDefinition",
                        "nodes": [],
                        "scope": 13,
                        "src": "66:19:2",
                        "usedErrors": []
                    }
                ],
                "src": "0:85:2"
            },
            "id": 2
        },
        "test/Counter.t.sol": {
            "ast": {
                "absolutePath": "test/Counter.t.sol",
                "exportedSymbols": {
                    "Counter": [
                        12
                    ],
                    "CounterTest": [
                        19
                    ],
                    "ERC20Mock": [
                        5
                    ]
                },
                "id": 20,
                "nodeType": "SourceUnit",
                "nodes": [
                    {
                        "id": 14,
                        "literals": [
                            "solidity",
                            "0.8",
                            ".13"
                        ],
                        "nodeType": "PragmaDirective",
                        "src": "0:23:3"
                    },
                    {
                        "absolutePath": "src/Counter.sol",
                        "file": "../src/Counter.sol",
                        "id": 16,
                        "nameLocation": "-1:-1:-1",
                        "nodeType": "ImportDirective",
                        "scope": 20,
                        "sourceUnit": 13,
                        "src": "24:43:3",
                        "symbolAliases": [
                            {
                                "foreign": {
                                    "id": 15,
                                    "name": "Counter",
                                    "nodeType": "Identifier",
                                    "overloadedDeclarations": [],
                                    "referencedDeclaration": 12,
                                    "src": "32:7:3",
                                    "typeDescriptions": {}
                                },
                                "nameLocation": "-1:-1:-1"
                            }
                        ],
                        "unitAlias": ""
                    },
                    {
                        "absolutePath": "lib/solady/ext/woke/ERC20Mock.sol",
                        "file": "lib/solady/ext/woke/ERC20Mock.sol",
                        "id": 18,
                        "nameLocation": "-1:-1:-1",
                        "nodeType": "ImportDirective",
                        "scope": 20,
                        "sourceUnit": 6,
                        "src": "68:60:3",
                        "symbolAliases": [
                            {
                                "foreign": {
                                    "id": 17,
                                    "name": "ERC20Mock",
                                    "nodeType": "Identifier",
                                    "overloadedDeclarations": [],
                                    "referencedDeclaration": 5,
                                    "src": "76:9:3",
                                    "typeDescriptions": {}
                                },
                                "nameLocation": "-1:-1:-1"
                            }
                        ],
                        "unitAlias": ""
                    },
                    {
                        "abstract": false,
                        "baseContracts": [],
                        "canonicalName": "CounterTest",
                        "contractDependencies": [],
                        "contractKind": "contract",
                        "fullyImplemented": true,
                        "id": 19,
                        "linearizedBaseContracts": [
                            19
                        ],
                        "name": "CounterTest",
                        "nameLocation": "138:11:3",
                        "nodeType": "ContractDefinition",
                        "nodes": [],
                        "scope": 20,
                        "src": "129:23:3",
                        "usedErrors": []
                    }
                ],
                "src": "0:152:3"
            },
            "id": 3
        }

from ethers-rs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.