新型solidity開發堆疊:buidler+ethers+waffle+typescript

買賣虛擬貨幣
以太坊的發展,雖然在感覺上還處於萌芽階段,但已經取得了不錯的進步。當我在2017年開始開發Solidity智慧合約和以太坊DAPP時,Truffle和Web3.js是行業標準。這些都是很棒的工具,我對建立它們的人表示敬意。雖然這類工具還不是很完善,在使用過程中會存在少些Bug,但是並不影響我們的正常使用。有一些新的工具顯然受到了這些第一組工具的啟發,使開發過程變得更好。我最近參加了一次駭客馬拉松,在那我不得不重新回顧並瞭解事物的當前狀態。我發現了很多很酷的工具,但是在文件上卻沒有太多關於如何使事情協同工作的工具。我決定寫下我的發現並建立一個專案,該專案可以作為任何想要構建和測試智慧合約和dapp的人的起點。Buidler(Truffle的替代工具)Buidler自稱是“以太坊智慧合約開發人員的任務管理者”。實際上,這意味著該工具將幫助您使用模板引導您的Solidity專案,併為您提供測試智慧合約並最終部署到以太坊區塊鏈所需的所有框架。以前是使用Truffle的 init, compile, test和migrate功能來引導Solidity專案是標準過程。Buidler吹捧的殺手級功能就是您的Solidity合約恢復的堆疊跟蹤。Ethers.js(取代Web3.js)Ethers.js是一個Javascript SDK用於與以太坊區塊鏈進行互動。在開始solidity開發時,我專門使用web3.js很長一段時間。當我第一次嘗試Ethers時,我對它的設定如此簡單以及API多麼出色感到震驚。我敦促曾經使用Web3.js的任何人嘗試一下Ethers。它具有使用錢包,帳戶和合約的所有必需功能,還具有一些簡潔的實用程式,例如ABICoder,HDNode,BigNumber,以及用於十六進位制字串,以太單位和以太坊地址的各種格式化實用程式。
Waffle (Truffle 測試的替代工具)以太坊Waffle是用於以太坊智慧合約的輕量級測試執行器。它內建了一些非常不錯的測試工具,例如用於以太坊地址,雜湊和BigNumbers的Chai匹配器,它是Typescript原生的,並且與Ethers的搭配非常好。Typescript對我來說,Typescript的絕對改變者是IDE整合,它為您提供了所有類屬性,物件鍵,函式引數等的自動完成功能。熟悉Typescript之後,我再也不會回過頭來編寫原始Javascript了。我上面提到的所有工具的優點是,它們都可以與Typescript一起很好地協作,並且一旦完成所有設定,開發人員的經驗是非常棒的。專案設定
現在開始做有趣的事情!在空資料夾中,透過執行npm init建立npm專案,在本練習的範圍內,將值設定為多少並不重要。安裝Buidler:$ npm install --save-dev @nomiclabs/buidler引導Buidler專案:$ npx buidler選擇“建立一個空的builder.config.js”選項(我們將使用與示例不同的堆疊,因此將建立自己的堆疊)。
$ npx buidler888               d8b      888 888888               Y8P      888 888888                        888 88888888b.  888  888 888  .d88888 888  .d88b.  888d888888 "88b 888  888 888 d88" 888 888 d8P  Y8b 888P"
888  888 888  888 888 888  888 888 88888888 888888 d88P Y88b 888 888 Y88b 888 888 Y8b.     88888888P"   "Y88888 888  "Y88888 888  "Y8888  888Welcome to Buidler v1.0.1 ? What do you want to do? …   Create a sample project
❯ Create an empty buidler.config.js  Quit建立一些目錄來儲存您的專案檔案:$ mkdir contracts test scripts設定Typescript安裝所需的Typescript依賴項:
$ npm install --save-dev ts-node typescript @types/node @types/mocha在專案根目錄中建立tsconfig檔案:{  "compilerOptions": {    "target": "es5",    "module": "commonjs",
    "strict": true,    "esModuleInterop": true,    "outDir": "dist"  },  "include": ["./scripts", "./test"],  "files": [
    "./buidler.config.ts"  ]}重新命名Builder配置檔案,並使其型別安全:mv buidler.config.js buidler.config.tsimport { BuidlerConfig } from "@nomiclabs/buidler/config";
const config: BuidlerConfig = {};export default config;建立和編輯合約現在,我們準備開始寫程式碼了!在contracts/目錄中建立一個名為counter.sol的非常簡單的solidity契約(編寫時最新的solidity版本是0.5.12):pragma solidity 0.5.12;
contract Counter {  uint256 count = 0;  event CountedTo(uint256 number);  function countUp() public returns (uint256) {    uint256 newCount = count + 1;    require(newCount > count, "Uint256 overflow");
    count = newCount;    emit CountedTo(count);    return count;  }  function countDown() public returns (uint256) {    uint256 newCount = count - 1;
    require(newCount < count, "Uint256 underflow");    count = newCount;    emit CountedTo(count);    return count;  }}

在buidler.config.ts中設定Solidity版本(自動完成型別註釋!):

Builder方便地捆綁了一個編譯任務,因此編譯是小菜一碟:

$ npx buidler compile
Compiling...
Compiled 1 contract successfully

Buidler使用的Solidity版本控制系統是令人驚歎的。 切換版本很容易,Buidler會根據需要自動下載並安裝Solidity版本,您所需要做的就是在配置中進行更改。 為Buidler團隊提供了巨大的道具來進行設定!

用Ethers和Waffle建立測試環境

現在,我們將設定您的測試環境。

安裝Ethers,Waffle和Builder外掛:

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

將所需的型別定義新增到tsconfig.json中:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "resolveJsonModule": true
  },
  "include": ["./scripts", "./test"],
  "files": [
    "./buidler.config.ts",
    "node_modules/@nomiclabs/buidler-ethers/src/type-extensions.d.ts",
}

設定builder.config.ts以使用Ethers外掛:

import { BuidlerConfig, usePlugin } from "@nomiclabs/buidler/config";
usePlugin("@nomiclabs/buidler-ethers");
const config: BuidlerConfig = {
  solc: {
    version: "0.5.12"
  }
};
export default config;

設定TypeChain

TypeChain是一個非常酷的工具,可為您的智慧合約提供完整的輸入介面。 設定完成後,我們可以在Typescript中獲得合同功能的型別提示!

在撰寫本文時,Buidler沒有TypeChain外掛。 如果有人不先做,我打算很快就自己建一個!

首先安裝庫和Ethers繫結:

$ npm install --save-dev typechain typechain-target-ethers

透過執行命令生成型別檔案。 outDir定義了生成檔案的儲存位置,最後用引號引起來的字串將提取構建目錄中所有生成的合同:

$ ./node_modules/.bin/typechain --target ethers --outDir typechain 'build/*.json'

現在在typechain /目錄中,您應該看到生成了一些檔案,其中一個是Counter.d.ts。 這是主要的合約型別檔案,為我們提供了編寫型別安全測試所需的資訊!

編寫和執行合約測試

編寫測試大多遵循Waffle語法,但有一個主要區別:ethers.provider物件是從“ @ nomiclabs / buidler”庫而不是ethereum-waffle庫匯入的。

現在讓我們編寫一個測試。 在test /目錄中建立一個名為counter.ts的檔案:

import { ethers } from "@nomiclabs/buidler";
import chai from "chai";
import { deployContract, getWallets, solidity } from "ethereum-waffle";

import CounterArtifact from "../build/Counter.json";
import { Counter } from "../typechain/Counter"

chai.use(solidity);
const { expect } = chai;

describe("Counter", () => {
  // 1
  const provider = ethers.provider;

  // 2
  let [wallet] = getWallets(provider);

  // 3
  let counter: Counter;

  beforeEach(async () => {
    counter = await deployContract(wallet, CounterArtifact) as Counter;
    const initialCount = await counter.getCount();

    // 4
    expect(initialCount).to.eq(0);
    expect(counter.address).to.properAddress;
  });

  // 5
  it("should count up", async () => {
    await counter.countUp();
    let count = await counter.getCount();
    expect(count).to.eq(1);

    await counter.countUp();
    count = await counter.getCount();
    expect(count).to.eq(2);
  });

  it("should count down", async () => {
    // 6
    await counter.countDown();
    const count = await counter.getCount();
    expect(count).to.eq(0);
  });
});

編號行的說明:

1.使用從Buidler匯入的provider

2.從getWallets功能獲取錢包另外請注意,您可以使用此函式對任意數量的錢包進行結構分解,例如:

let [wallet1, wallet2, wallet3] = getWallets(provider);

3.匯入Counter型別,並將其用作在beforeEach中部署的變數的型別。

4. Waffle有一些有用的Chai匹配器,用於編寫合同測試,例如BigNumber匹配器和以太坊地址匹配器。 在這裡檢視所有內容。

5.透過簡單的測試來計數並確保Counter正常工作。

6.注意的那些人將看到此測試將失敗。

讓我們開始執行測試!

$ npx buidler test

注意到結果有異常嗎?

All contracts have already been compiled, skipping compilation.

  Counter
    ✓ should count up (143ms)
    1) should count down

  1 passing (593ms)
  1 failing

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

這是您的Solidity程式碼中的STACK TRACE,其中顯示發生還原的行號!!! line逐行註釋合同以檢視觸發哪個還原的日子已經一去不復返了。

部署合約

經過測試後,迴圈的最後一步是部署合約。

第一步是將網路配置新增到buidler.config.ts檔案。 我們將為此使用rinkeby,但您可以類似地新增任何網路(即mainnet):

import { BuidlerConfig, usePlugin } from "@nomiclabs/buidler/config";
import waffleDefaultAccounts from "ethereum-waffle/dist/config/defaultAccounts";

usePlugin("@nomiclabs/buidler-ethers");

const INFURA_API_KEY = "";
const RINKEBY_PRIVATE_KEY = "";

const config: BuidlerConfig = {
  solc: {
    version: "0.5.12"
  },
  paths: {
    artifacts: "./build"
  },
  networks: {
    buidlerevm: {
      accounts: waffleDefaultAccounts.map(acc => ({
        balance: acc.balance,
        privateKey: acc.secretKey
      }))
    },
    rinkeby: {
      url: `https://rinkeby.infura.io/v3/${INFURA_API_KEY}`,
      accounts: [RINKEBY_PRIVATE_KEY]
    }
  }
};

export default config;

我將Infura用作以太坊節點端點,但是任何遠端端點都可以使用。 如果您從未這樣做,請從Infura獲取API金鑰。

現在,我們在指令碼/資料夾內建立一個名為deploy.ts的部署指令碼:

import { ethers } from "@nomiclabs/buidler";

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

超級簡單的東西!

現在,只需執行指令碼,我們就可以在控制檯中看到我們的地址和交易雜湊:

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

我們可以轉到Etherscan,檢視該事務實際上已成功完成。

你有它! 完整的分步指南,用於設定型別安全的增壓構建,測試,部署環境,並使用一些很酷的新工具。

收尾

為了使所有內容整潔無比,讓我們製作一些方便的NPM指令碼。 將以下內容新增到您的package.json中:

"scripts": {
  "build": "npm run compile && npm run typechain",
  "compile": "npx buidler compile",
  "typechain": "npx buidler compile && typechain --outDir typechain --target ethers 'build/*.json'",
  "test": "npx buidler test"
}

構建指令碼執行合同編譯並生成TypeChain繫結,並且測試指令碼執行合同測試。

 附加:在etherscan上驗證

Buidler有一個超級方便的外掛,可用於在Etherscan上驗證合約,此任務比看起來應該的要複雜得多。 他們的工具可以為您處理拼合,這對於匯入其他合約,使用OpenZeppelin庫等的合約非常方便。

我們可以從安裝外掛開始:

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

然後,我們新增到tsconfig.json中,以確保我們的Typescript環境瞭解此外掛:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "resolveJsonModule": true
  },
  "include": ["./scripts", "./test"],
  "files": [
    "./buidler.config.ts",
    "node_modules/@nomiclabs/buidler-ethers/src/type-extensions.d.ts",
    "node_modules/@nomiclabs/buidler-etherscan/src/type-extensions.d.ts"
  ]
}

接下來,我們將所需的配置新增到我們的buidler.config.ts中(跳到Etherscan並從您的帳戶頁面獲取API金鑰):

import { BuidlerConfig, usePlugin } from "@nomiclabs/buidler/config";
import waffleDefaultAccounts from "ethereum-waffle/dist/config/defaultAccounts";

usePlugin("@nomiclabs/buidler-ethers");
usePlugin("@nomiclabs/buidler-etherscan");

const INFURA_API_KEY = "";
const RINKEBY_PRIVATE_KEY = "";
const ETHERSCAN_API_KEY = "";

const config: BuidlerConfig = {
  solc: {
    version: "0.5.12"
  },
  paths: {
    artifacts: "./build"
  },
  networks: {
    buidlerevm: {
      accounts: waffleDefaultAccounts.map(acc => ({
        balance: acc.balance,
        privateKey: acc.secretKey
      }))
    },
    rinkeby: {
      url: `https://rinkeby.infura.io/v3/${INFURA_API_KEY}`,
      accounts: [RINKEBY_PRIVATE_KEY]
    }
  },
  etherscan: {
    // The url for the Etherscan API you want to use.
    url: "https://api-rinkeby.etherscan.io/api",
    // Your API key for Etherscan
    // Obtain one at https://etherscan.io/
    apiKey: ETHERSCAN_API_KEY
  }
};

export default config;

希望我們可以方便地保留上一步中的部署地址,因為這樣我們就可以簡單地執行此外掛提供的內建任務:

$ 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

易如反掌! 現在,在Etherscan上檢查合約地址,您可以檢視完整的合約原始碼,並直接從網頁上讀寫合約。

最後的想法

在整個使用過程中,Buidler對其devex的使用給我留下了深刻的印象。 它已經具有大量很酷的功能,並且他們計劃建造更多更酷的東西。 除了Solidity堆疊跟蹤,該團隊還計劃推出另一個急需的智慧合約除錯功能:console.log!。

我一定會密切關注這個專案,並盡我所能為其生態系統做出貢獻。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;