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