Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

import path canonicalization results in file paths that are not on disk #2609

Open
0xalpharush opened this issue Sep 19, 2023 · 11 comments
Open
Labels
bug Something isn't working

Comments

@0xalpharush
Copy link
Contributor

0xalpharush commented Sep 19, 2023

Version
Via Foundry
forge 0.2.0 (8c1a569 2023-09-19T00:32:46.118501000Z)

Platform
Darwin macbook arm64

Description
The build artifacts output by forge using ethers-solc are not consistently converting import paths into absolute paths with the root of the project resolved. These file paths cannot be opened bc they are not on disk and it's not ideal to have to search the project directory for candidates as there's potentially duplicates that are not interchangeable.

I think when foundry projects are nested, the root resolution is relative to the context of the dependency and not the project (however the example below demonstrates two different behaviors). This causes issues for tools like Slither because when a project takes a dependency on solmate and solady, there's ambiguity about which src/tokens/ERC20.sol is referenced and the given path isn't truly absolute.

How to create the project:

git clone git@github.com:0xalpharush/ethers-issue-2609.git && cd ethers-issue-2609
forge build --build-info

If I run cat out/ERC20Mock.sol/ERC20Mock.json | grep 'absolutePath": "src/tokens/ERC20.sol', there is a result that I do not expect.

Instead, I would expect the path for ERC20Mock to be absolute relative to the project root i.e. only the following command would return a result:

cat out/ERC20Mock.sol/ERC20Mock.json | grep 'absolutePath": "lib/solady/src/tokens/ERC20.sol'`

This expectation reflects the behavior of the import path resolution for Counter artifact which references the path, lib/solady/src/tokens/ERC20.sol :

cat out/Counter.sol/Counter.json | grep 'absolutePath": "lib/solady/src/tokens/ERC20.sol'`

Anywhere src/tokens/ERC20.sol appears in the build artifacts in reference to Solady, I would expect to see lib/solady/src/tokens/ERC20.sol (this is the behavior of hardhat and what I would consider correct as it's unambiguous)

I think the relevant code is here but I haven't figured out a solution yet. Also, I imagine this is particularly delicate and probably requires more context and consideration that I can provide...

if resolved.is_none() {
// absolute paths in solidity are a thing for example `import
// "src/interfaces/IConfig.sol"` which could either point to `cwd +
// src/interfaces/IConfig.sol`, or make use of a remapping (`src/=....`)
if let Some(lib) = self.find_library_ancestor(cwd) {
if let Some((include_path, import)) =
utils::resolve_absolute_library(lib, cwd, import)
{
// track the path for this absolute import inside a nested library
include_paths.insert(include_path);
return Ok(import)
}
}
// also try to resolve absolute imports from the project paths
for path in [&self.root, &self.sources, &self.tests, &self.scripts] {
if cwd.starts_with(path) {
if let Ok(import) = utils::canonicalize(path.join(import)) {
return Ok(import)
}
}
}
}

@0xalpharush 0xalpharush added the bug Something isn't working label Sep 19, 2023
@0xalpharush 0xalpharush changed the title path canonicalization results in file paths that are not on disk import path canonicalization results in file paths that are not on disk Sep 20, 2023
@mattsse
Copy link
Collaborator

mattsse commented Sep 20, 2023

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.

@0xalpharush
Copy link
Contributor Author

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

@mattsse
Copy link
Collaborator

mattsse commented Sep 20, 2023

fyi @Evalir

@plotchy
Copy link
Contributor

plotchy commented Oct 6, 2023

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?

@mattsse
Copy link
Collaborator

mattsse commented Oct 6, 2023

@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)

@plotchy
Copy link
Contributor

plotchy commented Oct 6, 2023

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?

@mattsse
Copy link
Collaborator

mattsse commented Oct 7, 2023

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

@plotchy
Copy link
Contributor

plotchy commented Oct 7, 2023

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": {}
  }
}

@plotchy
Copy link
Contributor

plotchy commented Oct 7, 2023

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.

@plotchy
Copy link
Contributor

plotchy commented Oct 7, 2023

@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

@0xalpharush
Copy link
Contributor Author

0xalpharush commented Oct 9, 2023

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
        }

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

No branches or pull requests

3 participants