Contract-Deployment

如何使用 Node.js 編譯 Solidity ^0.5.5 合約?

  • December 16, 2020

我是 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);
   });

});

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