0%

truffle | 通过 truffle + ganache 部署合约以及交互的全过程

我觉得写合约和写深度学习是一样的,对新手最不友好的地方就是配置环境。

你可能会遇到

  • truffle 下不下来
  • solc 特定版本下不下来
  • ganache 分叉的链非常不稳定
  • 写的合约部署不到 ganache 分叉的链上
  • 部署的时候总是出现莫名其妙的错误

每一个都让人十分崩溃,本文旨在写明从 0 开始搭建一个完整可运行的环境。


安装 truffle


npm 换镜像

一般人安装 truffle 都安装不了,经过我长时间测试,发现目前淘宝源起码还能安装上。虽然,大部分也安装不了。。。

所以,要更换一下 npm 的镜像,请参考

目前整体环境

  • node
    • 13.14

创建项目

初始化 npm

npm init

安装 truffle

请参考

注意,我的环境时 MBP

查看

truffle version

输出

Truffle v5.0.7 (core: 5.0.7)
Solidity v0.5.0 (solc-js)
Node v13.14.0

这里可以看出 solidity 的编译器是 0.5.0 版本的。


ganache


这里分叉的是 ETH 的主网。可以自己到 infura 上申请。

请参考

这里 ganache 的版本是 7

上面的博客部署是

ganache-cli --fork https://mainnet.infura.io/ws/v3/cbfde066e******

这样部署是为了在本地分叉主网,然后合约通过 127.0.0.1 部署。

但是,这样部署很容易出现下面的错误。

  • 错误1
    • const newErr = new Error(PollingBlockTracker - encountered an error while attempting to update latest block:\n${err.stack})
  • 错误2
    • Saving migration to chain.Error: TypeError: migrations.setCompleted is not a function
  • 错误3
    • Returned error: VM Exception while processing transaction: project ID does not have access to archive state.

经过我测试后,应该用 wss 进行分叉,这样就相对来说稳定一些。

ganache-cli --fork.url wss://mainnet.infura.io/ws/v3/cbfde06****

写合约


在 truffle 初始化的基础上,进行修改

Migrations.sol

1
2
3
4
5
6
7
pragma solidity >=0.4.22 <0.8.0;

contract Migrations {
function get() public pure returns (string memory){
return 'Hello Contracts';
}
}

truffle-config.js

1
2
3
4
5
6
7
networks: {
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
}

部署

truffle migrate --network development -f 1

这是部署在本地,然后会输出下面的样子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1_initial_migration.js
======================

Deploying 'Migrations'
----------------------
> account: 0xa2dfcFC197f811d0a53b537713Ae02a49485b0eB
> balance: 999.999726634
> gas used: 136683
> gas price: 2 gwei
> value sent: 0 ETH
> total cost: 0.000273366 ETH

TypeError: migrations.setCompleted is not a function
at Migration._deploy (/Users/licong/solidity/test/node_modules/truffle/build/webpack:/packages/truffle-migrate/migration.js:106:1)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at /Users/licong/solidity/test/node_modules/truffle/build/webpack:/packages/truffle-migrate/migration.js:60:1
Truffle v5.0.7 (core: 5.0.7)
Node v13.14.0

上面的错误是正常的,因为本地的分叉如果不进行设置,默认是不进行出块的,而,合约部署之后,会进行新块的请求,在稳定几个块之后才能保证你的合约部署上去了。

而,本地是不出块的,所以,获取不到,就报错了。

但是,如果没有输出

1
2
3
4
5
6
7
8
Deploying 'Migrations'
----------------------
> account: 0xa2dfcFC197f811d0a53b537713Ae02a49485b0eB
> balance: 999.999726634
> gas used: 136683
> gas price: 2 gwei
> value sent: 0 ETH
> total cost: 0.000273366 ETH

则证明没有部署成功,通常和 ganache 不稳定有关系。

但是,上面依然没有部署成功,因为它并没有输出合约地址。

我们修改 truffle_config.js

1
2
3
4
5
6
7
8
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
confirmations: 10,
timeoutBlocks: 200,
skipDryRun: true
}

这里里面的关键词

  • confirmations: 10,
    • 确认十个区块,证明已经部署
  • timeoutBlocks: 200,
  • skipDryRun: true
    • 这个暂时不知道什么意思,但是,必须要有这个,才能输出合约地址

配置 ganache 出块。

1
ganache-cli --fork wss://mainnet.infura.io/ws/v3/cbfde*** --miner.blockTime 3

加上上面的配置后,输出如下

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
1_initial_migration.js
======================

Deploying 'Migrations'
----------------------
> transaction hash: 0x322eef89b3b80424dc9346234a9c5a366af4cccfdb6e1d5dcacda94231750037
> Blocks: 0 Seconds: 0
> contract address: 0xa4d6a4ec630C2dBC4E8863e9D54A7Ec98ADAB378
> block number: 14852408
> block timestamp: 1653630077
> account: 0x5B50FB8420d314A23176Ba9E48b7F48c8454D0Cd
> balance: 999.998307157002599643
> gas used: 135103 (0x20fbf)
> gas price: 12.530017819 gwei
> value sent: 0 ETH
> total cost: 0.001692842997400357 ETH

Pausing for 10 confirmations...
-------------------------------
> confirmation number: 2 (block: 14852410)
> confirmation number: 3 (block: 14852411)
> confirmation number: 4 (block: 14852412)
> confirmation number: 6 (block: 14852414)
> confirmation number: 7 (block: 14852415)
> confirmation number: 8 (block: 14852416)
> confirmation number: 10 (block: 14852418)

⠋ Saving migration to chain.
TypeError: migrations.setCompleted is not a function
at Migration._deploy (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:99:1)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Migration._load (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:56:1)
at Migration.run (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:217:1)
at Object.runMigrations (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/migrate/index.js:150:1)
at Object.runFrom (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/migrate/index.js:110:1)
at runMigrations (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate.js:253:1)
at Object.run (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate.js:223:1)
at Command.run (/Users/licong/solidity/multiswap/node_modules/truffle/build/webpack:/packages/core/lib/command.js:183:1)
Truffle v5.4.12 (core: 5.4.12)
Node v16.13.1

虽然,依然有错误,但是,合约已经出来了,并且,能用。


交互


这里不通过 truffle console 进行交互,而是写 python 进行交互。

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
from web3 import Web3

from Constant.Strategy.StrategyConstant import StrategyType

abi = """[
{
"inputs": [],
"name": "get",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "pure",
"type": "function"
}
]"""


class Multiswap:
name = StrategyType.MULTISWAP.value

def __init__(self, strategyEngine):
self.web3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
self.strategyEngine = strategyEngine
self.multiswap = self.web3.eth.contract(
address=Web3.toChecksumAddress("0xa4d6a4ec630C2dBC4E8863e9D54A7Ec98ADAB378"), abi=abi)

def hello_world(self):
info = self.multiswap.functions.get().call()
print(info)


if __name__ == '__main__':
l = Multiswap(None)
l.hello_world()

其中 abi 的寻找,请看


更换 solc


这个目前没有真正的实现过,都是每次都有新的问题。

我觉得这个是最困难的,因为,网上关于怎么换的都说不清楚。

我曾经写过

经过我的测试得知,无论是 truffle 5.0.7 还是 5.0.22 适用都是 0.5.0 左右的 solc,一旦 solc 的版本上升到 0.6.0 左右,就会出现

TypeError: soljson.Pointer_stringify is not a function

错误,所以,我们只能升级 truffle 版本了。

经过我长时间的测试还有排查,终于找到一个可以使用 solc 0.8.0 的版本的 truffle。

那个版本就是

  • 5.4.12
请我喝杯咖啡吧~