怎样开始Solidity的学习
最近在学习区块链、智能合约相关知识,发现Solidity权威的学习资料很匮乏,很奇怪Solidity这么火竟然没有官方的详细学习资料,比如《Solidity Cookbook》这类书籍。
这篇文章是Solidity入门第一篇,关于如何搭建本地环境搭建。我个人也是新手,多年的语言学习体验还是习惯先有个本地的开发环境,Ethereum官方推荐的学习工具列举在下面:ethereum.org/zh/develope… ,其中Remix我看到很多人在推荐,如果喜欢在线编码的话可以直接使用。
另外,Solidity的入门学习材料推荐以下两个:
- CryptoZombie 讲的很泛但是方方面面都介绍到了,很适合建立初步的体感。
- Solidity By Example 我正在看,例子很多,但是貌似也没有介绍的很深入。
- 需要更加Advanced的学习资料。
Solidity本地环境我个人选择Truffle,我也是新手,如果大家有更好的推荐可以在评论区推荐给我,谢谢~
Truffle环境搭建
主要参考Truffle官方Quick Start:trufflesuite.com/docs/truffl…
安装很简单:
$ npm install -g truffle
强烈推荐安装Ganache,Ganache可以在本地启动一个带UI的eth链,带10个测试账号,每个账号有100个eth供测试用。
虽然Truffle也会启动本地的eth测试链,但是有个UI界面的Ganache还是很直观的,方便学习。
Ganache建议安装支持Filecoin的最新版本,虽然我们还没用到Filecoin,但是提前准备总是没错的。
参考:trufflesuite.com/docs/ganach…
所有可用的版本列表:github.com/trufflesuit…
手动安装最新版本,我用的版本是2.6.0-beta.3.1390,下载地址
Truffle一些操作技巧及常用命令
参考:trufflesuite.com/docs/truffl…
Truffle Quick Start里面的例子使用的MetaCoin,我们这里从truffle init开始建一个新的truffle工程。
1. 创建工程
$ mkdir test
$ cd test
$ truffle init
查看目录树:
$ tree .
.
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
└── truffle-config.js
\
3 directories, 3 files
2. 启动Ganache测试链
3. 配置Truffle Project连接到Ganache UI
图片里可以看到,Ganache的监听地址为http://127.0.0.1:7545 ,我们把这个地址配置到truffle-config.js里。
module.exports = {
...
networks: {
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
}
},
...
}
启动truffle console测试下是否成功:
$ truffle console
truffle(development)> let accounts = await web3.eth.getAccounts()
undefined
truffle(development)> accounts
[ '0xf0Ac7625E3D35B2eed3b6D96E3aeebeCBC5af091', '0x44CEfACE09E51dadAcaf153CE4f6Da90873D176c', '0x5E7DFEEDA81e3734B756c429dBE291Ad0a773Ef5', '0x357FAd25d64B1f66C5A1BD69bd57ce7f1846D203', '0xaca05A86BEB9D9D91a73B092E747eAbc0b629c1f', '0x10159311037dECc9aBCc32EEB1F5F93d8Db5fc02', '0x2B8D12e9A5E44C64673bDA343F5d5Db66752bcE0', '0x9581F92090bf2985e105d6Eb90cC1afFE05e6a34', '0xAB3DF6FEA353D55c64c5aC206D40f9eFa951DACf', '0x6587A514e15e59c7F8fb2Bfc0824707ba77004c2']
truffle(development)>.exit
注意用await关键字保障等待异步操作能正确返回。因为账户的生成是随机的,所以上面你的10个账户和我的不会相同。
4. 开发和部署新合约的一个示例
我们以solidity-by-example.org/payable 这里的一个example做示范,这个example里面包含了合约付款,是个不错的演示程序。
- 编写新合约
contracts/Payable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Payable {
// Payable address can receive Ether
address payable public owner;
// Payable constructor can receive Ether
constructor() payable {
owner = payable(msg.sender);
}
// Function to deposit Ether into this contract.
// Call this function along with some Ether.
// The balance of this contract will be automatically updated.
function deposit() public payable {}
// Call this function along with some Ether.
// The function will throw an error since this function is not payable.
function notPayable() public {}
// Function to withdraw all Ether from this contract.
function withdraw() public {
// get the amount of Ether stored in this contract
uint amount = address(this).balance;
// send all Ether to owner
// Owner can receive Ether since the address of owner is payable
(bool success, ) = owner.call{value: amount}("");
require(success, "Failed to send Ether");
}
// Function to transfer Ether from this contract to address from input
function transfer(address payable _to, uint _amount) public {
// Note that "to" is declared as payable
(bool success, ) = _to.call{value: _amount}("");
require(success, "Failed to send Ether");
}
}
大致讲解下:
- deposit:存eth进合约。
- notPayable: 调用这个函数时不可以付钱。
- withdraw:把这个合约内的所有钱都打给合约的owner。
- transfer:从这个合约里转移一定数额的钱给指定账户。
- 编写migration文件。
migration文件是指导truffle如何部署合约的文件,具体原理还没深入看过,目测是truffle会先部署一个deploy用的合约,后面的合约会借助这个deployer来做。
migrations/2_payable_migration.js
const Payable = artifacts.require("Payable");
module.exports = function (deployer) {
deployer.deploy(Payable);
};
- 部署
可以在命令行执行truffle migrate,或是在truffle console里执行migrate即可。
$ truffle migrate
Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/Payable.sol
> Artifacts written to /Users/zhangwei/program/crypto/test/build/contracts
> Compiled successfully using:
- solc: 0.8.13+commit.abaa5c0e.Emscripten.clang
Starting migrations...
======================
> Network name: 'development'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> transaction hash: 0xc5612b8e2f3c1f59627085ecfe1bbfd02f8426245e231ebcf6320b7676d46c23
> Blocks: 0 Seconds: 0
> contract address: 0xedF2d3b63b29bdE8ab015f7c306877BEE162eb23
> block number: 1
> block timestamp: 1654262832
> account: 0xf0Ac7625E3D35B2eed3b6D96E3aeebeCBC5af091
> balance: 99.99502292
> gas used: 248854 (0x3cc16)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00497708 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00497708 ETH
2_payable_migration.js
======================
Deploying 'Payable'
-------------------
> transaction hash: 0x4e6ec2f7b722deea05d0f9108d66b8b8a7e15877bb7b6a4bc2b77e34271b1a9e
> Blocks: 0 Seconds: 0
> contract address: 0x767836195C5A17217B3eeb2a9D2Fbe239B7Ea28D
> block number: 3
> block timestamp: 1654262832
> account: 0xf0Ac7625E3D35B2eed3b6D96E3aeebeCBC5af091
> balance: 99.98769456
> gas used: 323905 (0x4f141)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0064781 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.0064781 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.01145518 ETH
5. 与你的新合约交互
展示一下如何与你的合约交互,及一些常用的操作方法。
$ truffle console
truffle(development)> let accounts = await web3.eth.getAccounts()
undefined
truffle(development)> let instance = await Payable.deployed()
undefined
// accounts[1]存入3 ether,1 ether==10^18 wei
truffle(development)> instance.deposit({from:accounts[1], value:"3000000000000000000"})
......
注意,第一个合约只有99.99eth,0.01eth是在部署合约时作为Gas费燃烧掉了。 继续:
// 从合约里转移2ether给accounts[2]
truffle(development)> instance.transfer(accounts[2], "2000000000000000000")
继续:
// 剩下的所有钱(1eth)全部提取出来给owner(account[0])
truffle(development)> instance.withdraw()
6. 完结
基本就这样了,后续有别的操作技巧再来补充,bye~~