Solidity
尋找優雅的 solc 編譯器解決方案
我首先在我的契約中遇到了 import 語句的問題,我發現 solc 編譯器沒有處理 import 語句,我們需要自己製作。在一些好人的幫助下,我將這個腳本作為我自己的編譯器,並帶有一個處理導入語句的內置函式:
"use-strict"; const path = require("path"); const solc = require("solc"); //don"t forget to install the right solc version ! const fs = require("fs-extra"); // test folder const ERC20SourceCode = fs.readFileSync("./test/ERC20.sol"); // interfaces folder const IERC20SourceCode = fs.readFileSync("./interfaces/IERC20.sol"); const IUniswapV2CalleeSourceCode = fs.readFileSync("./interfaces/IUniswapV2Callee.sol"); const IUniswapV2ERC20SourceCode = fs.readFileSync("./interfaces/IUniswapV2ERC20.sol"); const IUniswapV2FactorySourceCode = fs.readFileSync("./interfaces/IUniswapV2Factory.sol"); const IUniswapV2PairSourceCode = fs.readFileSync("./interfaces/IUniswapV2Pair.sol"); // libraries folder const MathSourceCode = fs.readFileSync("./libraries/Math.sol"); const UQ112x112SourceCode = fs.readFileSync("./libraries/UQ112x112.sol"); const SafeMathSourceCode = fs.readFileSync("./libraries/SafeMath.sol"); // core folder const UniswapV2PairSourceCode = fs.readFileSync("./UniswapV2Pair.sol"); const UniswapV2ERC20SourceCode = fs.readFileSync("./UniswapV2ERC20.sol"); const UniswapV2FactorySourceCode = fs.readFileSync("./UniswapV2Factory.sol"); const buildPath = path.resolve(__dirname, "build"); fs.removeSync(buildPath); function compileContract(Contract) { const contractPath = path.resolve(__dirname, ...Contract); const contractSourceCode = fs.readFileSync(contractPath, "utf8"); fs.ensureDirSync(buildPath); var input = { language: "Solidity", sources: { Contract: { content: contractSourceCode } }, settings: { optimizer: { enabled: true }, outputSelection: { "*": { "*": [ "*" ] } } } }; function findImports(path) { if (path === "test/ERC20.sol") return { contents: `${ERC20SourceCode}` }; if (path === "interfaces/IUniswapV2Factory.sol") return { contents: `${IUniswapV2FactorySourceCode}` }; if (path === "interfaces/IERC20.sol") return { contents: `${IERC20SourceCode}` }; if (path === "interfaces/IUniswapV2Callee.sol") return { contents: `${IUniswapV2CalleeSourceCode}` }; if (path === "interfaces/IUniswapV2ERC20.sol") return { contents: `${IUniswapV2ERC20SourceCode}` }; if (path === "interfaces/IUniswapV2Pair.sol") return { contents: `${IUniswapV2PairSourceCode}` }; if (path === "libraries/Math.sol") return { contents: `${MathSourceCode}` }; if (path === "libraries/UQ112x112.sol") return { contents: `${UQ112x112SourceCode}` }; if (path === "libraries/SafeMath.sol") return { contents: `${SafeMathSourceCode}` }; if (path === "UniswapV2Pair.sol") return { contents: `${UniswapV2PairSourceCode}` }; if (path === "UniswapV2ERC20.sol") return { contents: `${UniswapV2ERC20SourceCode}` }; if (path === "UniswapV2Factory.sol") return { contents: `${UniswapV2FactorySourceCode}` }; else return { error: "File not found" }; } let output = JSON.parse(solc.compile(JSON.stringify(input), { import: findImports })); for(let contractName in output.contracts.Contract) { fs.outputJsonSync( path.resolve(buildPath, `${contractName}.json`), output.contracts.Contract[contractName] ); } } compileContract(["./", "UniswapV2Factory.sol"]); compileContract(["./", "UniswapV2Pair.sol"]); compileContract(["./", "UniswapV2ERC20.sol"]); compileContract(["./", "libraries", "Math.sol"]); compileContract(["./", "libraries", "SafeMath.sol"]); compileContract(["./", "libraries", "UQ112x112.sol"]); compileContract(["./", "interfaces", "IUniswapV2Factory.sol"]); compileContract(["./", "interfaces", "IERC20.sol"]); compileContract(["./", "interfaces", "IUniswapV2Callee.sol"]); compileContract(["./", "interfaces", "IUniswapV2ERC20.sol"]); compileContract(["./", "interfaces", "IUniswapV2Pair.sol"]); compileContract(["./", "test", "ERC20.sol"]);
我的問題是我是開發領域的新手,我希望有更多有經驗的人對這個解決方案的優雅提出意見。我是否正確使用了findImports功能?
我有很多if語句,這使得解決方案可能不是最優的。我還必須為我的契約中的每個導入語句儲存每個契約的原始碼……你自己會如何解決這個問題?
PS:這是我用來做這個的文件
我不知道為什麼我把它弄得這麼複雜,但是,是的,這是一個更優雅的版本!
function findImports(path) { const importSourceCode = fs.readFileSync(`./${path}`); return { contents: `${importSourceCode}` } }
如果有人有更好的答案,請隨時分享!但是這個滿足我現在的小技能(當路徑變得更複雜時,它仍然會變得更複雜一點,進入 node_modules 或其他文件夾)。
編輯:這是更複雜根的另一種解決方案。此功能適用於 uniswap v2 合約的外圍文件夾。基本上它處理:
- 從 node_module 導入
- 與已編譯合約位於同一文件夾中的合約(即無法使用已編譯合約的導入路徑從 compile.js 腳本訪問)
- 導入需要單向向上的路徑
- 根目錄中的導入路徑
這是功能:
function findImports(path) { let sourceCodeToImport; if(path[0] === "@") { // directly into node_ module sourceCodeToImport = fs.readFileSync(`../../../node_modules/${path}`); return { contents: `${sourceCodeToImport}` }; } if (arrayContractPath.length === 2) { // array contract path is "./" + contract.sol, i.e simple import in the same folder as the compile.js sourceCodeToImport = fs.readFileSync(`./${path}`); return { contents: `${sourceCodeToImport}` }; } if(!path.includes("/")) { // === contract to import is in the same folder as the contract we are compiling i.e the import path from the contract fiel doesn't include "/" sourceCodeToImport = fs.readFileSync(`./${intermediateFoldersOfCurrentContract}/${path}`); return { contents: `${sourceCodeToImport}` }; } else { // if neither of these, contract must be (in my case) accessible from the compile.js, i.e no need to change the path sourceCodeToImport = fs.readFileSync(`./${path}`); return { contents: `${sourceCodeToImport}` } } }
從 compile.js 文件中很難知道導入的合約是否在同一個文件夾中!因為路徑參數將與它以“./”或“../”開頭的參數相同……這使得它很難。但它工作:)
隨意接受並改進它。如果你確實改進它,請通知我。