# 使用truffle部署合约练习ethers库，对比web3js与ethers的使用

By [Easyplux](https://paragraph.com/@easyplux) · 2022-06-18

---

前言
--

使用 truffle部署合约，并练习ethers库。 之前一直是使用web3js，今天看到一个源码使用了ethers，看了之后感觉比web3js方便很多。

web3js 与 ethers对比
-----------------

### 连接到以太坊

    // web3 
    var Web3 = require('web3'); var web3 = new Web3('http://localhost:8545'); 
    // ethers 
    var ethers = require('ethers'); const url = "http://127.0.0.1:8545"; const provider = new ethers.providers.JsonRpcProvider(url);
    

### 签名对象

在ethers中，签名者是以太坊账户的抽象。它可用于对消息和交易进行签名，并将签名的交易发送到以太坊网络。 在 web3 中，可以使用一个帐户来签署消息和交易。

    // web3 
    const account = web3.eth.accounts.create(); 
    // ethers (create random new account) 
    const signer = ethers.Wallet.createRandom(); 
    // ethers (connect to JSON-RPC accounts) 
    const signer = provider.getSigner();
    

使用私钥生成账号对象生成调用的方法不同，不过使用上大同小异。

    // web3
    const signer = web3.eth.accounts.privateKeyToAccount(private_key)
    //ethers
    const signer = new ethers.Wallet(private_key);
    

### 账号签名

    // web3 (using a private key) 
    signature = web3.eth.accounts.sign('Some data', privateKey) 
    // ethers 
    signature = await signer.signMessage('Some data')
    

### 合约调用

#### 只读方法

    // web3js
    const contract = new this.web3.eth.Contract(abi, contract_address)
    const token_blance = await contract.methods.balanceOf(wallet_address).call()
    const blance = this.web3.utils.fromWei(token_blance, 'ether')
    
    // ethers
    const daiContract = new ethers.Contract(daiAddress, daiAbi, provider);
    const res = await daiContract.balanceOf(myaddress).toString()
    

上述方法中使用web3js需要去下载相应的ABI，比如你可以去etherscan下载，而在ethers中，你可以直接传入方法生成`daiAbi`

    const daiAbi = [
      // Some details about the token
      "function name() view returns (string)",
      "function symbol() view returns (string)",
    
      // Get the account balance
      "function balanceOf(address) view returns (uint)",
    
      // Send some of your tokens to someone else
      "function transfer(address to, uint amount)",
    
      // An event triggered whenever anyone transfers to someone else
      "event Transfer(address indexed from, address indexed to, uint amount)"
    ];
    const daiContract = new ethers.Contract(daiAddress, daiAbi, provider);
    

实践目标
----

1.使用truffle部署一个合约 2.使用truffle console 进行交互 3.使用ethers进行合约交互练习

### 安装环境

    yarn global add truffle
    yarn install ethers
    # 或者
    npm install -g truffle 
    npm install ethers
    

### 编写合约

实现一个最简单的合约

    // SPDX-License-Identifier: GPL-3.0
    
    pragma solidity 0.8.0;
    
    /**
     * @title Storage
     * @dev Store & retrieve value in a variable
     */
    contract Storage {
    
        uint256 number;
    
        /**
         * @dev Store value in variable
         * @param num value to store
         */
        function store(uint256 num) public {
            number = num;
        }
    
        /**
         * @dev Return value 
         * @return value of 'number'
         */
        function retrieve() public view returns (uint256){
            return number;
        }
    }
    

    # 编译
    truffle compile
    # 部署
    truffle migrate 
    

    
    Starting migrations...
    ======================
    > Network name:    'development'
    > Network id:      1
    > Block gas limit: 6721975 (0x6691b7)
    
    
    1_initial_migration.js
    ======================
    
       Replacing 'Migrations'
       ----------------------
       > transaction hash:    0x67c58fd2401c5bc506591f30b9566be6e8226c8b09a8125a511224cfa5029f7f
       > Blocks: 0            Seconds: 0
       > contract address:    0x25A6E016CB92D46fe8cE3f74D4F93b6439F6Cc89
       > block number:        14820726
       > block timestamp:     1653184639
       > account:             0x4BC9E31c338C402Aa2590E7008a879B5a66A8568
       > balance:             99.995114
       > gas used:            244300 (0x3ba4c)
       > gas price:           20 gwei
       > value sent:          0 ETH
       > total cost:          0.004886 ETH
    
    
       > Saving migration to chain.
       > Saving artifacts
       -------------------------------------
       > Total cost:            0.004886 ETH
    
    
    2_deploy_contracts.js
    =====================
    
       Replacing 'Storage'
       -------------------
       > transaction hash:    0x45ae44d9c9730485b0208dbbb0d1116398f9d562931024fc9757e5b603160cc1
       > Blocks: 0            Seconds: 0
       > contract address:    0xFe87778700B9dda2B5FD5fb7895120C33a331E69
       > block number:        14820728
       > block timestamp:     1653184640
       > account:             0x4BC9E31c338C402Aa2590E7008a879B5a66A8568
       > balance:             99.9918876
       > gas used:            118807 (0x1d017)
       > gas price:           20 gwei
       > value sent:          0 ETH
       > total cost:          0.00237614 ETH
    
    
       > Saving migration to chain.
       > Saving artifacts
       -------------------------------------
       > Total cost:          0.00237614 ETH
    
    
    Summary
    =======
    > Total deployments:   2
    > Final cost:          0.00726214 ETH
    

部署完成之后，我们可以使用 `truffle console` 进行交互

    let ins = await Storage.deployed()
    await ins.store(7)
    let n2 = await ins.retrieve()
    n2
    # BN { negative: 0, words: [ 7, <1 empty item> ], length: 1, red: null }
    

所以上述合约就只有2个方法 一个read方法：retrieve 一个write方法：store 所以通过 truffle 可以直接跟他进行交互 代码实现的功能：调用storage合约，将number修改为10，并且读取一次number的值。 ethers可以直接根据方法名生成abi，比web3js方便很多。

    const { ethers } = require("ethers");
    
    const provider = new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545");
    
    
    (async () => {
      const num = await provider.getBlockNumber();
      console.log(num);
      const singer = new ethers.Wallet(
        "private_key"
      );
      const myaddress = singer.address;
      console.log(myaddress);
      const signature = await singer.signMessage("some data");
      console.log(signature);
      const contractAddress = "0xFe87778700B9dda2B5FD5fb7895120C33a331E69";
    
      const storageAbi = [
        "function retrieve() view returns (uint256)",
    
        "function store(uint256 num)",
      ];
    
      // The Contract object
      const storageContract = new ethers.Contract(
        contractAddress,
        storageAbi,
        provider.getSigner()
      );
      const res = await storageContract.store(10);
      console.log(res);
    
      const res2 = await storageContract.retrieve();
      console.log(res2.toString());
    })();
    

综上所述，对比web3js，ethers封装了更方便的api接口，能简化一些调用流程。

参考
--

[Ethers Getting Started](https://docs.ethers.io/v5/getting-started/#getting-started--connecting-rpc)

---

*Originally published on [Easyplux](https://paragraph.com/@easyplux/truffle-ethers-web3js-ethers)*
