使用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开销。