如何在 NodeJS 上使用 Infura 和 web3js@1.xx 部署智能合約?
我有一個用 NodeJS 編寫的應用程序,每次啟動時都必須部署一個智能合約。部署合約後,此應用程序將與其互動,進行一些交易並監聽其事件。
關於進行交易、呼叫智能合約功能和監聽事件的部分工作正常,我無法做的事情是使用 NodeJS 部署智能合約。
要部署它,我必須通過命令行使用 truffle,然後啟動我的 NodeJS 應用程序並傳遞智能合約地址。通過這種方式,一切正常。
我發現一個非常難看的解決方法是通過直接從 NodeJS 應用程序執行控制台命令來自動執行此操作(處理 exec,擷取其輸出,解析字元串並找到合約地址……並且……是的,它有效!)。
顯然,我曾嘗試通過 Infura 進行操作,但沒有成功。為什麼?我不知道,但我可以解釋我做了什麼。由於部署智能合約不亞於進行正常交易,因此我準備、簽署並以與我上面引用的其他正常交易和合約函式呼叫相同的方式發送它。它似乎有效!但每次我得到兩個類似的錯誤:
- gas price * gas + value 不夠
- 如果我提高氣體,我會超過氣體限制
我幾乎可以肯定這不是關於氣體的問題,但在準備 > 簽名 > 發送的過程中還有其他問題。
請注意,我不需要在每次執行時編譯智能合約!ABI 和字節碼在每次執行時都相同,因此無需重新編譯即可遷移/部署它。
這是我用來部署智能合約失敗並返回氣體錯誤的 NodeJS 中的函式程式碼:
const amountToSend = 0.010000; const contract_PrintProofOfWork = new web3.eth.Contract(contractAbi, process.env.SMART_CONTRACT_ADDRESS, { from: web3.eth.defaultAccount, gasPrice: '10000000' }); async function getBalance(address) { let destinationBalanceWei = await web3.eth.getBalance(address); let destinationBalance = web3.utils.fromWei(destinationBalanceWei, 'ether'); return destinationBalance; } const getCurrentGasPrices = async () => { let response = await axios.get('https://ethgasstation.info/json/ethgasAPI.json'); let prices = { low: response.data.safeLow / 10, medium: response.data.average / 10, high: response.data.fast / 10 }; log("\r\n"); log('Current ETH Gas Prices (in GWEI):'); log(`Low: ${prices.low} (transaction completes in < 30 minutes)`); log(`Standard: ${prices.medium} (transaction completes in < 5 minutes)`); log(`Fast: ${prices.high} (transaction completes in < 2 minutes)`); log("\r\n"); return prices }; // This function is used to deploy contract const deploy = async () => { log(process.env.WALLET_ADDRESS); log(`Local PC wallet balance is currently ${await getBalance(web3.eth.defaultAccount)} ETH`.cyan); let deploy = contract_PrintProofOfWork.deploy({ data: contractByteCode //arguments: [] }).encodeABI(); let nonce = await web3.eth.getTransactionCount(web3.eth.defaultAccount); log(`The outgoing transaction count for your wallet address is: ${nonce}`.yellow); // Fetch the current transaction gas prices from https://ethgasstation.info/ let gasPrices = await getCurrentGasPrices(); // Build a new transaction object and sign it locally let transactionObject = { "to": process.env.DESTINATION_WALLET_ADDRESS, "value": web3.utils.toHex(web3.utils.toWei(amountToSend.toString(), 'ether')), "gas": 8000000, "gasPrice": gasPrices.high * 1000000000, // converts the gwei price to wei "nonce": nonce, "chainId": 3 // EIP 155 chainId - mainnet: 1, ropsten: 3, rinkeby: 4 (https://ethereum.stackexchange.com/questions/17051/how-to-select-a-network-id-or-is-there-a-list-of-network-ids/17101#17101) }; web3.eth.accounts.signTransaction(transactionObject, process.env.WALLET_PRIVATE_KEY, function (error, signedTx) { if (error) { log(`${error}`.red); } else { web3.eth.sendSignedTransaction(signedTx.rawTransaction) .on('confirmation', function (number) {//dostuff log(`Success: ${number}`.green); }); // Note this address. It will be used to create contract instance from Angular 5 application. //console.log("contract deployed to", result.options.address); } }).catch(function(err){ log(`${err}`.red); }); }; // Call deploy function. deploy();
錯誤:
(node:23315) UnhandledPromiseRejectionWarning: Error: Node error: {“code”:-32000,“message”:“insufficient fund for gas * price + value”} 在 Function.validate (/Users/sahelanthropus/IdeaProjects/ThesisPrototype/prototype -local-simple/node_modules/web3-providers/dist/web3-providers.cjs.js:349:18)在 /Users/sahelanthropus/IdeaProjects/ThesisPrototype/prototype-local-simple/node_modules/web3-providers/dist/web3 -providers.cjs.js:692:57 在 processTicksAndRejections (internal/process/next_tick.js:81:5)
或者,如果我提高要使用的氣體:
(node:23329) UnhandledPromiseRejectionWarning: Error: Node error: {“code”:-32000,“message”:“exceeds block gas limit”} at Function.validate (/Users/sahelanthropus/IdeaProjects/ThesisPrototype/prototype-local-simple /node_modules/web3-providers/dist/web3-providers.cjs.js:349:18)在 /Users/sahelanthropus/IdeaProjects/ThesisPrototype/prototype-local-simple/node_modules/web3-providers/dist/web3-providers.cjs .js:692:57 在 processTicksAndRejections (internal/process/next_tick.js:81:5)
任何人都可以簡單地告訴我如何使用
web3js
e部署智能合約,Infura
即使不參考程式碼和我在這個問題中暴露的問題?更新:
這是我的工作目錄的樣子:
PS C:\Projects\Eth_Dev\simple> ls Directory: C:\Projects\Eth_Dev\simple Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 27/02/2019 21:25 contracts d----- 27/02/2019 21:22 node_modules d----- 27/02/2019 21:25 test -a---- 27/02/2019 21:25 691 compile.js -a---- 27/02/2019 21:29 907 deploy.js -a---- 27/02/2019 21:22 152654 package-lock.json -a---- 27/02/2019 21:28 339 package.json
的內容
package.json
:{ "name": "myContract", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "mocha" }, "author": "", "license": "ISC", "dependencies": { "ganache-cli": "^6.2.5", "mocha": "^5.2.0", "solc": "^0.4.25", "truffle-hdwallet-provider": "0.0.3", "web3": "^1.0.0-beta.35" } }
除了我必須執行的唯一其他命令
npm install
是npm install --global --production windows-build-tools
的內容
contracts\myContract.sol
pragma solidity ^0.4.17; contract MyContract { string public message; function MyContract(string initialMessage) public { message = initialMessage; } function setMessage(string newMessage) public { message = newMessage; } }
這是一個似乎可以工作的 deploy.js 腳本。執行“node deploy.js”會部署到 Rinkeby 網路
const HDWalletProvider = require('truffle-hdwallet-provider'); const Web3 = require('web3'); const {interface, bytecode} = require('./compile'); const provider = new HDWalletProvider( 'your twelve word mnemonic', 'https://rinkeby.infura.io/v3/YOUR_API_KEY' ); const web3 = new Web3(provider); const deploy = async () => { const accounts = await web3.eth.getAccounts(); console.log('Attempting to deploy from account', accounts[0]); const result = await new web3.eth.Contract(JSON.parse(interface)) .deploy({data:bytecode, arguments:['This is deployed!']}) .send({gas:'1000000', from: accounts[0]}); console.log('Contract deployed to ', result.options.address); }; deploy();
有一個編譯文件的引用。compile.js 看起來像這樣:
const path = require('path'); //builds a path from the current file. const fs = require('fs'); //Need the solidity compiler const solc = require('solc'); //__dirname will get the inbox dir path. //look in the contracts folder and get a path to the Inbox.sol file. const myContractPath = path.resolve(__dirname,'contracts','myContract.sol'); //Read in the contents of the file. The raw source code. const source = fs.readFileSync(myContractPath,'utf8'); //console.log(solc.compile(source,1)); //This will export the compiled file. Make it available //At the moment only interested in the Inbox contract. module.exports = solc.compile(source,1).contracts[':MyContract'];
和輸出:
PS C:\Projects\Eth_Dev\simple> node .\deploy.js Attempting to deploy from account 0x15ec...B Contract deployed to 0x5...2DA9269a