Recursively generating OpenZeppelin dependencies

My team is building a cloud IDE for Solidity files and want to allow users to import OpenZeppelin components into their smart contracts.

The Solidity compiler needs to be passed a list of sources and their file contents to compile for import statements to work. Thus, the source file needs to be parsed and all of the dependencies recursively generated so they can be included in the compiler standard input JSON.

To make this happen on our platform we maintain the latest version (v4.6.0) of the OpenZeppelin contract repository in a cloud storage location. Before a user actually compiles a contract, our web application will call an API method on our server that attempts to generate all the necessary sources for the OpenZeppelin imports.

This is the progress I've made toward the method and obviously it isn't ready for production yet, I'm trying to brush up on tail recursion to get this working but was wondering if the community would be willing to collaborate on this.

async function getDependencies(ozFileName) {
  // Fetch the file content from cloud storage
  const fetchPath = ozFileName.replace(
    '@openzeppelin',
    'https://candystorage171338-dev.s3.amazonaws.com/public/openzeppelin-4.6.0'
  );
  const fetchedData = await fetch(fetchPath);
  const fetchedSourceContent = await fetchedData.text();
  // Use the @solidity-parser/parser package to parse the OpenZeppelin contract
  const ast = parser.parse(fetchedSourceContent);
  // Visit each ImportDirective and get the dependencies for each of those files
  parser.visit(ast, {
    ImportDirective: async function (node) {
      return getDependencies(node.path);
    }
  });
}

app.post('/parse', async function (req, res) {
  // Pass the source file in the body of the API request
  let input = req.body.source;
  // Collect the OpenZeppelin imports
  try {
    var allDependencies = [];
    var ozImports = [];
    const ast = parser.parse(input);
    // Visit each node
    parser.visit(ast, {
      ImportDirective: function (node) {
        // Only target @openzeppelin imports and not local project imports
        if (node.path.split('/') == '@openzeppelin')
          // Add the path to output
          ozImports.push(node.path);
      }
    });
    // Loop over each @openzeppelin import and recursively generate
    // the dependencies for each one
    for (var i = 0; i < ozImports.length; i++) {
      var dependencies = getDependencies(ozImports[i]);
      allDependencies.push(dependencies);
    }
    res.json({ parsedInput: ast, imports: imports });
  } catch (e) {
    // There was an error in execution
    res.json({ error: e });
  }
});

Packages

1 Like

It sounds like great! And it seems like a tool like the Remix.

And how about using some decentralized storage, like IPFS?

Thanks! It is very similar to Remix but designed to be more user-friendly. It will also feature automatic ethers.js and web3.js boilerplate code generation and other helpful features. The last missing piece is this recursive dependency generation and then we'll be able to launch the beta version of the IDE.

1 Like

How about listing all dependencies and then remove the duplicate dependencies, or maybe you can have a look how the remix do for this.