Solidity

我們如何通過 compile.js 文件編譯多個智能合約?

  • July 12, 2021

我的 compile.js 文件在下面

const path = require('path');

const fs = require('fs');

const solc = require('solc');

const ballotPath = path.resolve(__dirname, 'contracts', 'blocktitans_ballot.sol');

const source = fs.readFileSync(ballotPath, 'utf8');

module.exports = solc.compile(source, 1).contracts[':blocktitans_ballot'];

我需要幫助導出多個合約的 abi 和字節碼以編寫測試腳本。

上面的 compile.js 腳本適用於單個契約,但我如何編譯多個契約並導出它們?

您有兩種可能性 a) 您自己的建構腳本或 b) 僅使用 truffle 框架。第一種選擇是直截了當,但有一些缺點。當您開始編寫合約時,最好了解 sol 編譯器的工作方式,但稍後 truffle 框架會幫助您管理更複雜的場景(例如遷移、測試、部署和對 etherscan 的驗證請求)。

要回答您的問題(使用單個腳本建構多個契約):

這段程式碼是我去年做的一個項目的早期腳本。在此程式碼中,您編譯了一個名為 CertificateManagement.sol 的主合約以及來自 OpenZeppelin 庫的一些依賴項,用於角色管理以及 Migrations.sol 程式碼。

// Dependencies
const solc = require("solc");
const fs = require("fs");

// Parameter default values
let BUILD_TARGET_PATH = './build/';

let contractBuild = async () => {

   // Creates target path in the case it doesn't exists
   fs.mkdir(BUILD_TARGET_PATH, {recursive: true}, (err) => {
       if (err) throw err;

       // loading the source code from a solidity file
       let input = {
           language: 'Solidity',
           sources: {
               //
               // CertificateManagement.sol
               'CertificateManagement.sol': {
                   content: fs.readFileSync('contracts/CertificateManagement.sol', 'utf8'),
               },
               //
               // Pausable.sol
               'openzeppelin/lifecycle/Pausable.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/lifecycle/Pausable.sol', 'utf8'),
               },
               './openzeppelin/lifecycle/Pausable.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/lifecycle/Pausable.sol', 'utf8'),
               },
               //
               // PauserRole.sol
               './openzeppelin/access/roles/PauserRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/PauserRole.sol', 'utf8'),
               },
               '../access/roles/PauserRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/PauserRole.sol', 'utf8'),
               },
               'openzeppelin/access/roles/PauserRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/PauserRole.sol', 'utf8'),
               },
               //
               // Roles.sol
               'Roles.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
               },
               '../Roles.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
               },
               '../access/Roles.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
               },
               './openzeppelin/access/Roles.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
               },
               'openzeppelin/access/Roles.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
               },
               //
               // WhitelistedRole.sol
               'openzeppelin/access/roles/WhitelistedRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistedRole.sol', 'utf8'),
               },
               //
               // WhitelistAdminRole.sol
               'WhitelistAdminRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistAdminRole.sol', 'utf8'),
               },
               './WhitelistAdminRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistAdminRole.sol', 'utf8'),
               },
               'openzeppelin/access/roles/WhitelistAdminRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistAdminRole.sol', 'utf8'),
               },
               //
               // WhitelistedRole.sol
               'WhitelistedRole.sol': {
                   content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistedRole.sol', 'utf8'),
               },
               //
               // Migrations.sol
               'Migrations.sol': {
                   content: fs.readFileSync('contracts/Migrations.sol', 'utf8'),
               },
           },
           settings: {
               outputSelection: {'*': {'*': ['*']}}
           }
       };

       // compile the solidity code
       let compiled = solc.compile(JSON.stringify(input));
       console.log("Compiling    -> OK" );
       let output = JSON.parse(compiled);

       for (let contractJson in output.contracts) {
           if (contractJson.startsWith("CertificateManagement.")) {
               fs.writeFile(BUILD_TARGET_PATH + '/' + contractJson.replace(".sol", ".json"), JSON.stringify(output.contracts[contractJson][contractJson.replace(".sol", "")]), function (err) {
                   console.log("\nJSON saved   -> OK\n    "+ BUILD_TARGET_PATH + contractJson.replace(".sol", ".json"));
                   if (err) throw err;
               });
           }
       }

       // Save bytecode
       let bytecode = '0x' + output.contracts['CertificateManagement.sol']['CertificateManagement'].evm.bytecode.object;
       console.log('\nByte Code    -> OK');

       fs.writeFile(BUILD_TARGET_PATH + 'CertificateManagement.bytecode', bytecode, function (err) {
           console.log("\nCode saved   -> OK\n    "+ BUILD_TARGET_PATH + "CertificateManagement.bytecode");
           if (err) throw err;
       });

       // Logging of methods
       console.log('\nIndentifiers -> OK\n');
       let methodIdentifiers = output.contracts['CertificateManagement.sol']['CertificateManagement'].evm.methodIdentifiers;
       for (let indentifier in methodIdentifiers) {
           console.log("    " + indentifier);
       }

       // save public interface of contract
       let abi = output.contracts['CertificateManagement.sol']['CertificateManagement'].abi;
       fs.writeFile(BUILD_TARGET_PATH + 'CertificateManagement.abi', JSON.stringify(abi), function (err) {
           console.log("\nABI saved    -> OK\n    "+ BUILD_TARGET_PATH + "CertificateManagement.abi");
           console.log(" ");
           if (err) throw err;
       });
   });
};

contractBuild();

我猜—通過在這些契約的 ballotPath 中添加 .sol 文件名和–通過將數字 1 更改為要編譯的契約數,例如 2,3 等–並從 .contracts 中刪除:blocktitans_ballot在模組導出中,以便涵蓋所有契約。

如果我不正確,請提前道歉。謝謝。

引用自:https://ethereum.stackexchange.com/questions/58131