Contract-Deployment
使用 solc 編譯導入本地 OpenZeppelin 合約的合約
我正在嘗試使用 Node.js 編譯和部署基於 OpenZeppelin 的契約
app.get("/", (req, res) => { const input = fs.readFileSync("./BaseContract.sol", "utf8"); const compiledInput = solc.compile(input); ... });
但是,當呼叫此函式時,出現以下錯誤
ParserError: Source \"node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol\" not found: File not supplied initially.\nimport \"./node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol\";
這是我的契約
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Base is ERC721 { constructor() ERC721("Base", "BAS") { } function mint( address _to, uint256 _tokenId ) external { _safeMint(_to, _tokenId); } }
我已經使用 將@openzeppelin 安裝到 node_modules 中
yarn add @openzeppelin/contracts
,相關文件位於 node_modules 文件夾中。我知道 solc 無法通過網路獲取,但文件是在本地安裝的,所以這不應該是問題。我可以做些什麼來解決這裡問題?
我遇到了這個錯誤,因為我沒有指定 solc 的所有相關來源(版本 ^0.8.0)。我通過編寫一個遞歸函式來解決這個問題,該函式以正確的格式編譯所有依賴項。
const fs = require("fs"); const solc = require("solc"); // returns a contract object compiled using solc // baseContractPath: relative path of the base contract, i.e. "./BaseContract.sol" const instantiateContract = (baseContractPath) => { const sources = {}; compileImports(baseContractPath, sources); var input = { language: "Solidity", sources: sources, settings: { outputSelection: { "*": { "*": ["*"], }, }, }, }; const output = solc.compile(JSON.stringify(input)); const contract = JSON.parse(output); const bytecode = "0x" + contract.contracts[baseContractPath]["Base"].evm.bytecode.object; const abi = contract.contracts[baseContractPath]["Base"].abi; return { bytecode: bytecode, abi: abi, }; }; // returns sources: { "Contract.sol": { content: fs.readFileSync("pathName.sol",utf8)...}} // using recursion const compileImports = (root, sources) => { sources[root] = { content: fs.readFileSync(root, "utf8") }; const imports = getNeededImports(root); for (let i = 0; i < imports.length; i++) { compileImports(imports[i], sources); } }; // returns all the import paths in absolute path const getNeededImports = (path) => { const file = fs.readFileSync(path, "utf8"); const files = new Array(); file .toString() .split("\n") .forEach(function (line, index, arr) { if ( (index === arr.length - 1 && line === "") || !line.trim().startsWith("import") ) { return; } // the import is legit const relativePath = line.substring(8, line.length - 2); const fullPath = buildFullPath(path, relativePath); files.push(fullPath); }); return files; }; // parent: node_modules/.../ERC721/ERC721.sol // returns absolute path of a relative one using the parent path const buildFullPath = (parent, path) => { let curDir = parent.substr(0, parent.lastIndexOf("/")); //i.e. ./node/.../ERC721 if (path.startsWith("./")) { return curDir + "/" + path.substr(2); } while (path.startsWith("../")) { curDir = curDir.substr(0, curDir.lastIndexOf("/")); path = path.substr(3); } return curDir + "/" + path; }; module.exports = { instantiateContract, };
--allow-path
作為 solc 中的一項安全措施,您不能編譯來自您所在目錄的父文件夾或相鄰文件夾的合約。您可以使用如下方式逐一添加要允許編譯的路徑:--allow-path "/path/to/folderOne" --allow-path "/path/to/folderTwo"
更好的選擇是使用
truffle compile
,建構一個新的 truffle 項目或將您的契約添加到現有項目並使用該truffle compile
命令,它將自動添加路徑,沒有任何麻煩。