【轉譯】全新合約開發(fā)技術棧:Hardhat + Ethers + Waffle + Typescript

英文原文地址:https://rahulsethuram.medium.com/the-new-solidity-dev-stack-buidler-ethers-waffle-typescript-tutorial-f07917de48ae
原文發(fā)表日期:2020-02-09

【譯文省略了很多原作者抒情性文字,直接進入主題捏膨。】
本文相關代碼:Starter Kit repo

Hardhat (替代Truffle)

Hardhat 稱自己為“task runner for Ethereum smart contract developers”满粗。 在實踐中爱谁,Hardhat 將幫助你使用模板啟動 Solidity 項目晒喷,并提供測試及部署智能合約所需的所有腳手架。 之前访敌,使用 Truffle 初始化 truffle init凉敲,編譯 truffle compile ,測試 truffle test 和部署 truffle migrate 功能來推動Solidity項目寺旺。

Hardhat的殺手級功能是堆棧跟蹤信息爷抓,使得在調試 Solidity 時,可以使用回退(revert)和console.log()阻塑。

Ethers.js (替代Web3.js)

Ethers.js 是一個Javascript SDK蓝撇,用于與以太坊區(qū)塊鏈進行交互。 我從使用Solidity開發(fā)以來陈莽,一直使用Web3.js渤昌。 當我第一次嘗試Ethers.js時,我對它如此簡單及API的出色程度感到震驚走搁。 我推薦曾經(jīng)使用Web3.js的任何人嘗試一下Ethers.js独柑。 它擁有針對錢包,帳戶和合約的所有必需功能朱盐,并且還具有一些簡潔的實用程序群嗤,例如ABICoder,HDNode兵琳,BigNumber狂秘,以及用于十六進制字符串,以太單位轉換和以太坊地址的各種格式化實用工具躯肌。

Waffle (替代Truffle 測試工具)

Ethereum Waffle 是以太坊智能合約的輕量級測試運行器者春。 Waffle內(nèi)置了一些非常不錯的測試工具函數(shù),例如用于以太坊地址清女,哈希和BigNumbers的Chai匹配器钱烟,Waffle使用原生Typescript,與Ethers.js配合非常好嫡丙。

譯者注:Chai 是一個斷言庫拴袭,使用鏈式結構進行斷言。

Typescript 無處不在

Typescript 最近很火曙博,這是有原因的拥刻。 對我而言,Typescript 的最大的改變是 IDE的集成父泳,它提供所有類屬性般哼,對象鍵吴汪,函數(shù)參數(shù)等的自動補全功能。熟悉Typescript之后蒸眠,我再也不會回過頭來編寫原始Javascript了漾橙。

上面提到的所有工具都可以與Typescript一起很好地工作,并且一旦完成所有設置楞卡,開發(fā)的體驗很夢幻霜运。

項目啟動(Project setup)

現(xiàn)在開始真正有趣的實踐! 在一個空文件夾中臀晃,運行以下命令初始化一個npm項目:

npm init

初始化過程中觉渴,需要多項目有一個簡單的設置,因為我們只是演練徽惋,可以隨意填。

安裝 Hardhat:

$ npm install --save-dev hardhat

譯者注座韵,如果npm 安裝慢险绘,本文的npm 命令都可以用cnpm替換

進行Hardhat項目引導:

$ npx hardhat

選擇"Create an empty hardhat.config.js"選項,意思是常見一個新的而不是參考一個樣例誉碴。

$ npx buidler
888               d8b      888 888
888               Y8P      888 888
888                        888 888
88888b.  888  888 888  .d88888 888  .d88b.  888d888
888 "88b 888  888 888 d88" 888 888 d8P  Y8b 888P"
888  888 888  888 888 888  888 888 88888888 888
888 d88P Y88b 888 888 Y88b 888 888 Y8b.     888
88888P"   "Y88888 888  "Y88888 888  "Y8888  888

?? Welcome to Buidler v1.3.8 ??

? What do you want to do? … 
  Create a sample project
? Create an empty hardhat.config.js
  Quit

創(chuàng)建一些目錄來保存項目文件宦棺,命令如下:

$ mkdir contracts test scripts

設置 Typescript

安裝Typescript需要的依賴項:

$ npm install --save-dev ts-node typescript @types/node @types/mocha

在根目錄中創(chuàng)建tsconfig文件:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist"
  },
  "include": ["./scripts", "./test"],
  "files": [
    "./hardhat.config.ts"
  ]
}

重命名hardhat配置文件,修改后綴并使其類型安全:

mv hardhat.config.js hardhat.config.ts

//  hardhat.config.ts
import { HardhatUserConfig } from "hardhat/types";

const config: HardhatUserConfig = {};

export default config;

創(chuàng)建和編譯合約

現(xiàn)在可以開始編寫代碼:

在 contracts/ 目錄創(chuàng)建一個非常簡單的 Counter.sol 合約文件(當前使用的最新Solidity 版本是 0.6.8):

pragma solidity ^0.6.8;
import "hardhat/console.sol";

contract Counter {
  uint256 count = 0;

  event CountedTo(uint256 number);

  function getCount() public view returns (uint256) {
    return count;
  }

  function countUp() public returns (uint256) {
    console.log("countUp: count =", count);
    uint256 newCount = count + 1;
    require(newCount > count, "Uint256 overflow");
    count = newCount;
    emit CountedTo(count);
    return count;
  }

  function countDown() public returns (uint256) {
    console.log("countDown: count =", count);
    uint256 newCount = count - 1;
    require(newCount < count, "Uint256 underflow");
    count = newCount;
    emit CountedTo(count);
    return count;
  }
}

在hardhat.config.ts中通過修改solidity.compilers.$.version 來設置Solidity版本:

譯者注黔帕,此處可能是舊版本才需要修改代咸,新版本config內(nèi)結構也不盡相同

hardhat 集成了編譯任務,因此編譯是小菜一碟:

> npx builder compile
Compiling...
Compiled 1 contract successfully

hardhat使用AMAZING 來對Solidity進行版本控制成黄。 切換版本很容易呐芥,hardhat會根據(jù)需要自動下載并安裝Solidity版本,您所需要做的就是在配置中進行更改奋岁。 hardhat團隊提供了很多選項進行設置思瘟!你可以通過將config文件中solidity key賦值為數(shù)組(array),而很簡單的編譯出不同solidity版本的項目闻伶。

使用Ethers和Waffle配置測試環(huán)境

現(xiàn)在滨攻,創(chuàng)建一個測試環(huán)境,安裝 Ethers, Waffle, 以及 Buidler 插件:

$npm install --save-dev ethers @nomiclabs/buidler-waffle ethereum-waffle

在tsconfig.json添加需要的類型定義:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "resolveJsonModule": true
  },
  "include": [
    "./scripts",
    "./test"
  ],
  "files": [
    "./hardhat.config.ts"
  ]
}

設置 hardhat.config.ts 以便使用 waffle 插件

import { HardhatUserConfig } from "hardhat/types";
import "@nomiclabs/hardhat-waffle";
const config: HardhatUserConfig = {
  solidity: {
    compilers: [{ version: "0.6.8", settings: {} }],
  },
};
export default config;

設置 TypeChain

TypeChain 是一款非忱逗玻酷的工具光绕,可為智能合約提供完整的類型接口。 設置完成后畜份,我們可以在Typescript中獲得合約函數(shù)的類型提示诞帐!

可以通過我構建的Typechain插件使用,先安裝:

$ npm install --save-dev hardhat-typechain typechain ts-generator @typechain/ethers-v5

Builder配置文件中添加 typechain以配置插件:

import { HardhatUserConfig } from "hardhat/types";
import "@nomiclabs/hardhat-waffle";
import "hardhat-typechain";
const config: BuidlerConfig = {
  solidity: {
    compilers: [{ version: "0.6.8", settings: {} }],
  },
};
export default config;

編譯

& npx hardhat compile

現(xiàn)在漂坏,進入目錄 typechain/ 景埃,你可以看到一些生成的文件媒至,其中有一個是 Counter.d.ts 。這是主要的合同文件谷徙。

編寫和運行合約測試

編寫測試大多遵循Waffle語法拒啰,但有一個主要區(qū)別:ethers.provider 對象是從 hardhat 庫而不是 ethereum-waffle 庫導入的。

現(xiàn)在讓我們編寫一個測試完慧。 在 test/ 目錄中創(chuàng)建一個名為counter.ts的文件:

import { ethers } from "hardhat";
import chai from "chai";
import { solidity } from "ethereum-waffle";
import { Counter } from "../typechain/Counter";
chai.use(solidity);
const { expect } = chai;
describe("Counter", () => {
  let counter: Counter;
  beforeEach(async () => {
    // 1
    const signers = await ethers.getSigners();
    // 2
    const counterFactory = await ethers.getContractFactory(
      "Counter",
      signers[0]
    );
    counter = (await counterFactory.deploy()) as Counter;
    await counter.deployed();
    const initialCount = await counter.getCount();
    // 3
    expect(initialCount).to.eq(0);
    expect(counter.address).to.properAddress;
  });
  // 4
  describe("count up", async () => {
    it("should count up", async () => {
      await counter.countUp();
      let count = await counter.getCount();
      expect(count).to.eq(1);
    });
  });
  describe("count down", async () => {
    // 5
    it("should fail", async () => {
      // this test will fail
      await counter.countDown();
    });
    it("should count down", async () => {
      await counter.countUp();
    await counter.countDown();
      const count = await counter.getCount();
      expect(count).to.eq(0);
    });
  });
});

代碼中幾處標記處解釋如下:

  1. 從Ethers獲取一寫預先存款的簽名器谋旦。
  2. 使用從 1 獲取的簽名器部署合約。 導入 Counter 類型屈尼,并將其作為 beforeEach 中部署的變量的類型册着。
  3. Waffle有一些有用的Chai匹配器可用于編寫合約測試,例如BigNumber匹配器和以太坊地址匹配器脾歧。 在這里查看所有內(nèi)容甲捏。
  4. 簡單計數(shù)測試,確保計數(shù)器正常工作鞭执。
  5. 此測試將失敗司顿,值得關注,等下會看到 Hardhat 的真正魔力兄纺。

讓我們運行測試大溜。

首先,我們將Hardhat配置為使用其hardhat網(wǎng)絡估脆,該網(wǎng)絡提供了所有Solidity調試魔法:

import { HardhatUserConfig } from "hardhat/types";

import "[@nomiclabs/hardhat-waffle](http://twitter.com/nomiclabs/hardhat-waffle)";
import "hardhat-typechain";

const config: HardhatUserConfig = {
  defaultNetwork: "hardhat",
  solidity: {
    compilers: [{ version: "0.6.8", settings: {} }],
  },
};

export default config;

現(xiàn)在運行測試:

$ npx hardhat test

注意在結果中有不尋常的內(nèi)容:

2 passing (1s)
  1 failing

1) Counter
       count down
         should fail:
     Error: VM Exception while processing transaction: revert Uint256 underflow
      at Counter.countDown (contracts/Counter.sol:29)

它打印了Solidity 的輸出以及堆棧信息钦奋,顯示了觸發(fā)回退的行號!!! ??????

逐行注釋合約以查看觸發(fā)了哪個還原(revert)去猜測變量值的日子已經(jīng)一去不復返了。

譯者注:這里原作者稍微有點夸張疙赠,其實現(xiàn)在其他工具鏈也會給出 revert 原因付材。

部署合約

經(jīng)過測試后,開發(fā)周期的最后一步是部署合約棺聊。

第一步是將網(wǎng)絡配置添加到hardhat.config.ts文件伞租。 為此,本案例我們將使用rinkeby限佩,但您可以類似地添加任何網(wǎng)絡(如:mainnet)葵诈,配置很簡單:

import { HardhatUserConfig } from "hardhat/types";

import "[@nomiclabs/hardhat-waffle](http://twitter.com/nomiclabs/hardhat-waffle)";
import "hardhat-typechain";

const config: HardhatUserConfig = {
  defaultNetwork: "hardhat",
  solidity: {
    compilers: [{ version: "0.6.8", settings: {} }],
  },
  networks: {
    hardhat: {},
    rinkeby: {
      url: `[https://rinkeby.infura.io/v3/${INFURA_API_KEY}`],
      accounts: [RINKEBY_PRIVATE_KEY],
    },
  },
};

export default config;

我將Infura用作以太坊節(jié)點,不過你可以使用任何遠程以太坊節(jié)點祟同。 如果你之前沒有使用過 Infura作喘,請從Infura獲取API密鑰。

現(xiàn)在晕城,我們在 scripts 文件夾內(nèi)創(chuàng)建一個名為deploy.ts的部署腳本:

import { ethers } from "hardhat";
async function main() {
  const factory = await ethers.getContract("Counter");
  // If we had constructor arguments, they would be passed into deploy()
  let contract = await factory.deploy();
  // The address the Contract WILL have once mined
  console.log(contract.address);
  // The transaction that was sent to the network to deploy the Contract
  console.log(contract.deployTransaction.hash);
  // The contract is NOT deployed yet; we must wait until it is mined
  await contract.deployed();
}
main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });

部署非常簡單泞坦,現(xiàn)在運行這個腳本,我們在控制臺可以看到地址及交易hash.

$ npx hardhat run --network rinkeby scripts/deploy.ts
All contracts have already been compiled, skipping compilation.
0x01FF454Dd078dC7f3cd0905601d093b17E7B9CD7
0x2ae1444920ed76420fb69c9f2fc914c20956efc2ae05c94ab1ea53f224aa0930

我們可以前往 Etherscan 查看交易詳情砖顷。

這基本就是全部了贰锁,本文一步步進行創(chuàng)建項目測試赃梧、部署環(huán)境,他們都是類型安全的并且使用一些很酷的工具豌熄。

封裝一下

為了使一切保持干凈漂亮授嘀,讓我們編寫一些順手的NPM腳本。 將以下內(nèi)容添加到您的package.json中:

"scripts": {
  "build": "npm run compile",
  "compile": "npx buidler compile",
  "test": "npx buidler test"
}

build 用于執(zhí)行合約編譯并生成TypeChain綁定

test 腳本運行合約測試锣险。

福利: 在Etherscan上驗證

Hardhat有一個超級方便的插件蹄皱,可用于在Etherscan上驗證合約,此任務其實比看起來要復雜芯肤。 Hardhat的工具可以為幫我們處理合約組合巷折,當我們導入了其他合約,例如使用了OpenZeppelin等庫的合約會非常方便崖咨。

安裝插件:

$ npm install --save-dev @nomiclabs/hardhat-etherscan

接下來锻拘,我們在hardhat.config.ts中添加所需的配置,前往Etherscan并從您的帳戶頁面獲取API密鑰:

import { HardhatUserConfig } from "hardhat/types";

import "[@nomiclabs/hardhat-waffle](http://twitter.com/nomiclabs/hardhat-waffle)";
import "hardhat-typechain";

const config: HardhatUserConfig = {
  defaultNetwork: "hardhat",
  solidity: {
    compilers: [{ version: "0.6.8", settings: {} }],
  },
  networks: {
    hardhat: {},
    rinkeby: {
      url: `[https://rinkeby.infura.io/v3/${INFURA_API_KEY}`](https://rinkeby.infura.io/v3/$%7BINFURA_API_KEY%7D%60),
      accounts: [RINKEBY_PRIVATE_KEY],
    },
  },
  etherscan: {
    // Your API key for Etherscan
    // Obtain one at [https://etherscan.io/](https://etherscan.io/)
    apiKey: ETHERSCAN_API_KEY,
  },
};

export default config;

希望我們可以順手保存上一步的部署地址掩幢,因為這樣就可以簡單地運行插件提供的內(nèi)置命令來驗證合約:

$ npx buidler verify-contract --contract-name Counter --address 0xF0E6Ea29799E85fc1A97B7b78382fd034A6d7864

All contracts have already been compiled, skipping compilation.
Successfully submitted contract at 0xF0E6Ea29799E85fc1A97B7b78382fd034A6d7864 for verification on etherscan. Waiting for verification result...
Successfully verified contract on etherscan

非常簡單逊拍! 現(xiàn)在,在Etherscan上查看合約地址际邻,可以查看到完整的合約源代碼,并在網(wǎng)頁上讀寫合約芍阎。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末世曾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子谴咸,更是在濱河造成了極大的恐慌轮听,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岭佳,死亡現(xiàn)場離奇詭異血巍,居然都是意外死亡,警方通過查閱死者的電腦和手機珊随,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門述寡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人叶洞,你說我怎么就攤上這事鲫凶。” “怎么了衩辟?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵螟炫,是天一觀的道長。 經(jīng)常有香客問我艺晴,道長昼钻,這世上最難降的妖魔是什么掸屡? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮然评,結果婚禮上仅财,老公的妹妹穿的比我還像新娘。我一直安慰自己沾瓦,他們只是感情好满着,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贯莺,像睡著了一般风喇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缕探,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天魂莫,我揣著相機與錄音,去河邊找鬼爹耗。 笑死耙考,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的潭兽。 我是一名探鬼主播倦始,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼山卦!你這毒婦竟也來了鞋邑?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤账蓉,失蹤者是張志新(化名)和其女友劉穎枚碗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铸本,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡肮雨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了箱玷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怨规。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汪茧,靈堂內(nèi)的尸體忽然破棺而出椅亚,到底是詐尸還是另有隱情,我是刑警寧澤舱污,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布呀舔,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏媚赖。R本人自食惡果不足惜霜瘪,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惧磺。 院中可真熱鬧颖对,春花似錦、人聲如沸磨隘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽番捂。三九已至个唧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間设预,已是汗流浹背徙歼。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鳖枕,地道東北人魄梯。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像宾符,于是被迫代替她去往敵國和親酿秸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 以太坊開發(fā)者工具的最新終極清單魏烫,用于在以太坊上開發(fā)應用程序的可用工具允扇,組件,框架和平臺的指南则奥。 對于任何開發(fā)者,無...
    編程狂魔閱讀 1,130評論 0 5
  • 1. 以太坊堆棧介紹 Like any software stack, the complete "Ethereu...
    龍小治閱讀 1,257評論 0 1
  • 根據(jù)英文原版整理狭园,內(nèi)容有增刪 1读处、開發(fā)語言、框架與工具 語言 Solidity - 官方推薦以太坊智能合約開發(fā)語言...
    Rakutens閱讀 851評論 0 2
  • 使用 Infura 和 web3.js交互 Infura 提供公開的 Ethereum 主網(wǎng)和測試網(wǎng)路節(jié)點通過AP...
    jiangfengzh閱讀 718評論 0 0
  • 1 開發(fā)語言唱矛、框架與工具 語言 Solidity - 官方推薦以太坊智能合約開發(fā)語言罚舱,也是目前最為主流的智能合約語...
    宇宙永恒閱讀 141評論 0 1