Contract-Deployment
如何使用 Node.js 編譯 Solidity ^0.5.5 合約?
我是 Solidity 的新手,現在我嘗試學習如何在 Solidity ^0.5.5 中編譯合約(以下沒有版本)。
我的契約如下(UsersContract.sol)
pragma solidity ^0.5.5; contract UsersContract { struct User { string name; string surname; } mapping(address => User) private users; mapping(address => bool) private joinedUsers; address[] total; event OnUserJoined(address, string); function join(string memory name, string memory surname) public { require(!userJoined(msg.sender)); User storage user = users[msg.sender]; user.name = name; user.surname = surname; joinedUsers[msg.sender] = true; total.push(msg.sender); emit OnUserJoined(msg.sender, string(abi.encodePacked(user.name, " ", user.surname))); } function getUser(address addr) public view returns (string memory, string memory) { require(userJoined(msg.sender)); User memory user = users[addr]; return (user.name, user.surname); } function userJoined(address addr) private view returns (bool){ return joinedUsers[addr]; } function totalUsers() public view returns (uint){ return total.length; } }
接下來是編譯器(compile.js):
const path = require('path'); const fs = require('fs'); const solc = require('solc'); const contractPath = path.join(__dirname,'../contracts','UsersContract.sol'); const source = fs.readFileSync(contractPath, 'UTF-8'); const input = { language: 'Solidity', sources: { 'UsersContract.sol': { content: source } }, settings: { outputSelection: { '*': { '*': [ '*' ] } } } } function findImports (path) { if (path === 'UsersContract.sol') return { contents: source } else return { error: 'File not found' } } const output = JSON.parse(solc.compile(JSON.stringify(input), findImports)); module.exports.output = output;
最後是我之前執行測試以執行它們的文件(UsersContract.test.js)
const assert = require('assert'); const Web3 = require('web3'); const provider = new Web3.providers.HttpProvider("HTTP://127.0.0.1:7545"); // GANACHE RPC SERVER const web3 = new Web3(provider); const { interface, bytecode } = require('../contracts/compile.js'); let accounts; let usersContract; beforeEach(async() => { accounts = await web3.eth.getAccounts(); usersContract = await new web3.eth.Contract(JSON.parse(interface)) .deploy({ data: bytecode }) .send({ from: accounts[1], gas: 1000000}); }); describe('The UsersContract', async() => { it('should deploy', () => { console.log(usersContract.options.address); assert.ok(usersContract.options.address); }); });
主要問題是,每次我執行npx mocha來嘗試測試時,我都會收到下一個錯誤:
The UsersContract 1) "before each" hook for "should deploy" 0 passing (59ms) 1 failing 1) "before each" hook for "should deploy": SyntaxError: Unexpected token u in JSON at position 0 at JSON.parse (<anonymous>) at Context.beforeEach (test/UsersContract.test.js:24:54) at <anonymous> at process._tickCallback (internal/process/next_tick.js:182:7)
有什麼幫助嗎?任何的想法?我不知道我現在在哪里或做錯了什麼。
PD:我在這裡放了 package.json 資訊。希望能幫助到你。
{ "name": "compile-and-deploy", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "mocha" }, "author": "", "license": "ISC", "dependencies": {}, "devDependencies": { "mocha": "^5.2.0", "solc": "^0.5.5", "web3": "^1.0.0-beta.35" } }
最後,我找到了一種使用 Node.js 編譯 Solidity ^0.5.5 合約的方法。關鍵是正確使用 JSON。
在UsersContract.test.js中,我們需要傳遞舊介面和字節碼,如下所示:
const assert = require('assert'); const Web3 = require('web3'); const provider = new Web3.providers.HttpProvider("HTTP://127.0.0.1:7545"); const web3 = new Web3(provider); const compiled_contract = require('../contracts/compile.js'); const interface_abi = compiled_contract.output.contracts['UsersContract.sol']['UsersContract'].abi; const bytecode = compiled_contract.output.contracts['UsersContract.sol']['UsersContract'].evm.bytecode.object; let accounts; let usersContract; beforeEach(async() => { accounts = await web3.eth.getAccounts(); usersContract = await new web3.eth.Contract(interface_abi) .deploy({ data: bytecode }) .send({ from: accounts[1], gas: 1000000}); }); describe('The UsersContract', async() => { it('should deploy', () => { console.log(usersContract.options.address); assert.ok(usersContract.options.address); }); });