前言

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

web3js 与 ethers对比

连接到以太坊

1
2
3
4
// 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 中,可以使用一个帐户来签署消息和交易。

1
2
3
4
5
6
// 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();

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

1
2
3
4
5
// web3
const signer = web3.eth.accounts.privateKeyToAccount(private_key)
//ethers
const signer = new ethers.Wallet(private_key);

账号签名

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

合约调用

只读方法

1
2
3
4
5
6
7
8
9
// 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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进行合约交互练习

安装环境

1
2
3
4
5
yarn global add truffle
yarn install ethers
# 或者
npm install -g truffle
npm install ethers

编写合约

实现一个最简单的合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 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;
}
}
1
2
3
4
# 编译
truffle compile
# 部署
truffle migrate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

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 进行交互

1
2
3
4
5
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方便很多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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