# 使用Hardhat與Infura部署合約 **Published by:** [weippig](https://paragraph.com/@weippig/) **Published on:** 2022-05-08 **URL:** https://paragraph.com/@weippig/hardhat-infura ## Content 原文發佈在個人網站小試身手1.Retrieve the Current Block Numbercurl [https://mainnet.infura.io/v3/](https://mainnet.infura.io/v3/YOUR-PROJECT-ID)YOUR_PROJECT_ID \ -X POST \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params": [],"id":1}' 回傳了以十六進制表示的block number:{"jsonrpc":"2.0","id":1,"result":"0xdf9bca"} 2.Check the Ether Balance For a Given Contractcurl [https://rinkeby.infura.io/v3/](https://mainnet.infura.io/v3/YOUR-PROJECT-ID)YOUR_PROJECT_ID \ -X POST \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_getBalance","params": ["0xBf4eD7b27F1d666546E30D74d50d173d20bca754", "latest"],"id":1}' 回傳{"jsonrpc":"2.0","id":1,"result":"0x159fa21f4e8b7e715de0"} ,result中的字串代表合約的balance,單位是wei,一個Ether約等於10¹⁸ wei。建立交易看看吧1.建立Ethereum帳號(可使用例如metamask) 2.建資料夾立然後進入mkdir sendTransaction cd sendTransaction 3.安裝需要的packagesnpm install web3 npm install dotenv --save 💡 `dotenv` package用來讓使用者建立.env檔案、安全地存放本地環境變數。 4.建立.env檔案,內容:ETHEREUM_NETWORK = "rinkeby" INFURA_PROJECT_ID = "<Project-ID>" SIGNER_PRIVATE_KEY = "<Private-Key>" 在infura dashboard→setting 內可以找到 以太坊帳號私鑰,導出metamask私鑰可看這篇ETHEREUM_NETWORK 因自己在哪個網路而異,不一定是rinkeby5.建立send.js檔案,內容:const Web3 = require("web3"); async function main() { // Configuring the connection to an Ethereum node const network = process.env.ETHEREUM_NETWORK; const web3 = new Web3( new Web3.providers.HttpProvider( `https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}` ) ); // Creating a signing account from a private key const signer = web3.eth.accounts.privateKeyToAccount( process.env.SIGNER_PRIVATE_KEY ); web3.eth.accounts.wallet.add(signer); // Creating the transaction object const tx = { from: signer.address, to: "0xAED01C776d98303eE080D25A21f0a42D94a86D9c", value: web3.utils.toWei("0.001"), }; // Assigning the right amount of gas tx.gas = await web3.eth.estimateGas(tx); // Sending the transaction to the network const receipt = await web3.eth .sendTransaction(tx) .once("transactionHash", (txhash) => { console.log(`Mining transaction ...`); console.log(`https://${network}.etherscan.io/tx/${txhash}`); }); // The transaction is now on chain! console.log(`Mined in block ${receipt.blockNumber}`); } require("dotenv").config(); main(); 6.執行 7.可到輸出結果第二行的網址查看細節結合Hardhat部署合約到測試鏈上吧前置作業1.安裝Hardhatnpm install --save-dev hardhat 2.建立資料夾並進入mkdir infura_project cd infura_project 3.建立Hardhat project,選擇第一個 Create a basic sample project4.MacOS的環境下,可以使用 tree -L 1 指令印出第一層資料夾樹狀結構,沒有安裝過tree的話,可透過 brew install tree 安裝撰寫合約與測試1.將contract資料夾底下的Greeter.sol改名為Demo.sol,替換程式碼內容為://SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol"; contract Demo is Ownable{ uint256 private _value = 0; event ValueChanged(uint256 value); function store(uint256 value) public onlyOwner { _value = value; emit ValueChanged(value); } function retrieve() public view returns (uint256) { return _value; } } 2.合約需要用到openzepplin的Ownable.sol,使用指令安裝@openzeppelin/contractsnpm install @openzeppelin/contracts 3.編譯合約看看 會列印出 Compiled 3 Solidity files successfully,資料夾目錄底下多出artifacts和cache兩個資料夾 4.將test資料夾底下的sample-test.js 改名為Demo.test.ts,內容為:import { expect } from 'chai' import { ethers } from 'hardhat' // Start test block describe('Demo', function () { before(async function () { this.Demo = await ethers.getContractFactory('Demo') }) beforeEach(async function () { this.demo = await this.Demo.deploy() await this.demo.deployed() }) // Test case it('retrieve returns a value previously stored', async function () { // Store a value await this.demo.store(42) // Test if the returned value is the same one // Note that we need to use strings to compare the 256 bit integers expect((await this.demo.retrieve()).toString()).to.equal('42') }) }) 這時候會報錯,這是因為我們接下來會用typescript進行開發,需要更改package.json內容:{ "name": "hardhat-project", "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.0.5", "@nomiclabs/hardhat-waffle": "^2.0.3", "@types/chai": "^4.3.1", "@types/mocha": "^9.1.1", "@types/node": "^17.0.27", "chai": "^4.3.6", "dotenv": "^16.0.0", "ethereum-waffle": "^3.4.4", "ethers": "^5.6.4", "hardhat": "^2.9.3", "mocha": "^9.2.2", "solc": "^0.8.13", "ts-node": "^10.7.0", "typescript": "^4.6.3", "web3": "^1.7.3" }, "dependencies": { "@openzeppelin/contracts": "^4.5.0", "@typechain/hardhat": "^6.0.0" } } 再執行一次 npm install ,回到Demo.test.ts就看不到紅字了! 5.更改hardhat.config.js成.ts,檔頭require("@nomiclabs/hardhat-waffle"); 改為import { task } from "hardhat/config"; import "@nomiclabs/hardhat-waffle"; import "@nomiclabs/hardhat-ethers"; 6.添加tsconfig.json檔案{ "compilerOptions": { "target": "ES2017", "module": "commonjs", "declaration": true, "declarationMap": true, "sourceMap": true, "outDir": "./dist", "strict": true, "rootDirs": ["./src", "./scripts", "./test"], "esModuleInterop": true }, "exclude": ["dist", "node_modules"], "include": ["./test", "./src", "./scripts"], "files": ["./hardhat.config.ts"] } 7.使用 npx hardhat test 指令進行測試,順利的話,最後會出現 1 passing撰寫腳本進行部署1.將scripts資料夾下的sample-scripts.js更改為deploy.ts,內容為:import { ethers } from "hardhat"; async function main() { const [deployer] = await ethers.getSigners(); //get the account to deploy the contract console.log("Deploying contracts with the account:", deployer.address); const Demo = await ethers.getContractFactory("Demo"); // Getting the Contract const demo = await Demo.deploy(); //deploying the contract await demo.deployed(); // waiting for the contract to be deployed console.log("Demo deployed to:", demo.address); // Returning the contract address on the rinkeby } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); // Calling the function to deploy the contract 2.在hardhat.config.ts中配置網路,添加在solidity: "0.8.4"後面export default { solidity: "0.8.4", defaultNetwork: "rinkeby", networks: { hardhat: { }, rinkeby: { url: "https://rinkeby.infura.io/v3/YOUR_PROJECT_ID", //Infura url with projectId accounts: ["YOUR_ACCOUNT_PRIVATE_KEY"] // add the account that will deploy the contract (pay gas fee) } }, 3.執行指令 TS_NODE_FILES=true ts-node scripts/deploy.ts ,如果是使用測試鏈,可能需要等待比較久的時間,成功後應該會看到結果:上面是部署合約、支付gas fee的帳號,下面是合約地址,把合約地址複製起來,去Etherscan看看:4.在scrips資料夾底下建立叫做storeAndRetrieve.ts的新檔案,測試剛剛部署好的合約的兩個function,store()和retrieve()import { ethers } from "hardhat"; async function main () { const accounts = await ethers.provider.listAccounts(); const address = 'YOUR_CONTRACT_ADDRESS'; const Demo = await ethers.getContractFactory('Demo'); const demo = await Demo.attach(address); // Call the retrieve() function of the deployed Box contract let value = await demo.retrieve(); console.log('demo value is', value.toString()); } main() .then(() => process.exit(0)) .catch(error => { console.error(error); process.exit(1); }); 5.使用 TS_NODE_FILES=true ts-node scripts/storeAndRetrieve.ts 指令執行,會呼叫合約中的retrieve(),印出_value原始的值0。監聽合約事件1.在主目錄底下建立src資料夾,裡面建立一個做eventListener.ts的檔案import { ethers } from 'hardhat' async function listenEvent () { const address = 'YOUR_CONTRACT_ADDRESS' const Demo = await ethers.getContractFactory('Demo') const demo = await Demo.attach(address) demo.on('ValueChanged', async (event: any) => { console.log(event) }) } listenEvent() 2.修改storeAndRetrieve.ts,在let value = await demo.retrieve(); 前面加上三行,代表呼叫合約中的store(uint value),並變更_value的值成100// Send a transaction to store() a new value let storeValue = await demo.store(100); await storeValue.wait(); 3.執行指令 TS_NODE_FILES=true ts-node src/eventListener.ts 持續監聽合約內的事件 ValueChanged 4.在新的terminal分頁執行 TS_NODE_FILES=true ts-node scripts/storeAndRetrieve.ts 5.過了一陣子,回到剛剛執行eventListener.ts的地方,因為呼叫store function來存入100,觸發了事件ValueChanged,合約監聽器會印出BigNumber { value: “100” } 6.可以回到Etherscan做確認,應該會看到兩筆交易,兩筆事件資料來源:Getting Started With InfuraDeploying and interacting with smart contractsHardhat-typescript ## Publication Information - [weippig](https://paragraph.com/@weippig/): Publication homepage - [All Posts](https://paragraph.com/@weippig/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@weippig): Subscribe to updates