使用solidity开发以太坊智能合约
一些开发合约相关资料
- 合约开发语言:soliditylang;中文版
 - 开发工具:remix-project
 - 开发网络:ganache,hardhat,scaffold-eth:以太坊开发all in one
 - solc版本列表
 
环境搭建(MAC)
安装solidity
1  | brew install solidity  | 
安装truffle
truffle是集成安装、部署、测试合约为一体的开发框架;如果没有node环境需要先安装node:brew install node
1  | npm install truffle -g  | 
合约开发
初始化项目路径
1  | truffle init  | 
初始化npm环境
在初始化的过程中会让你输入一些参数的值,可以一路按回车全部使用默认值即可
1  | npm init  | 
安装npm依赖库
1  | npm install dotenv truffle-wallet-provider ethereumjs-wallet  | 
配置网络
1  | module.exports = {  | 
开发合约
按照《精通以太坊》书本的例子写了一个“水龙头”的合约,只有两个函数,一个提取以太币(withdraw),一个接收以太币(receive)。合约的代码放在项目的contracts目录下。
1  | // SPDX-License-Identifier: GPL-3.0  | 
编译合约
1  | truffle compile  | 
部署合约
参考migrations/1_initial_migration.js文件,新建一个``migrations/2_initial_migration.js;(*注意:2_initial_migration.js这个名字不能以0`开头,否则部署的时候会忽略。。。*)修改文件内容如下:
1  | const Faucet = artifacts.require("Faucet");  | 
然后部署到本地的测试网络(要在本地启动truffle的ethereum测试网络):
1  | truffle migrate --network localnode  | 
执行完成之后的日志如下:
1  | (base) w:Faucet apple$ truffle migrate --network localnode  | 
使用truffle部署智能合约到ropsten测试网络
可以在https://infura.io/网站建立账号,可以把它看成一个geth节点,然后他提供了rpc接口。
首次执行部署,报错说HDWalletProvider没有定义
1  | truffle migrate --network ropsten  | 
解决方案:
添加依赖:
1  | npm install truffle-hdwallet-provider  | 
在与truffle-config.js相同的目录下添加.evn文件,然后写入你的助记词,如:
1  | mnemonic=topic foster find apple famous have bonus month remain middle funny smart  | 
注意在gitignore文件中把这个文件(.evn)忽略,避免上传到github
修改truffle-config.js:在最上面添加:
1  | // 在使用infura作为rpc-api的提供方时,因为infura不管理我们的私钥所以要在本地有一个钱包用于签名  | 
修改ropsten的配置如下:
1  | ropsten: {  | 
重新部署:
1  | truffle migrate --network ropsten  | 
原因是没有足够的汽油费,去https://faucet.ropsten.be/获取即可。
在此重新部署:
1  | truffle migrate --network ropsten  | 
调用合约的报错汇总:
1  | Received unexpected error:  | 
1  | intrinsic gas too low: have 0, want 21420 (supplied gas 0)  | 
上面这些全部都是因为gas费设置的太少导致的。
与合约交互
在remix中调用合约
在remix网页中部署完成合约之后,在下面可以看到withdraw函数,输入提现的金额然后点击transact按钮,就可以调起MetaMask调用智能合约。

使用truffle的命令调用合约
启动truffle的console控制台:
1  | truffle console --network localnode  | 
打开之后双击两次tab键会有命令提示,我们查看一下部署的Faucet合约的地址:
1  | Faucet.address  | 
查看我们合约的账户余额:
1  | web3.eth.getBalance(Faucet.address)  | 
truffle develop
develop Open a console with a local development blockchain
1  | Faucet.deployed().then(i => {FaucetDeployed = i})  | 
与Gas费相关的注意事项
如果在执行过程中gas费耗尽,会触发如下一系列事件:
- 抛出“out of gas”异常
 - 状态被恢复到执行开始之前
 - 所有在这次执行过程中的gas开销都会被作为交易费用,以太坊不会因为交易中止而退回gas或以太币。
 
如何把合约函数调用的gas费消耗最小化
避免动态尺寸的数组
例如对数组的每个元素进行操作,或者通过遍历的方式查找数组中的某个值。
避免调用其他合约
调用其他合约,特别是那些gas消耗未知的合约,可能会产生高昂的gas开销。