Skip to content

Commit

Permalink
polish chapter 1
Browse files Browse the repository at this point in the history
  • Loading branch information
AmazingAng committed May 6, 2023
1 parent 2b37ac1 commit 6ae3920
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 55 deletions.
75 changes: 43 additions & 32 deletions 01_HelloWeb3/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,65 +18,76 @@ tags:

-----

## Solidity简述
`Solidity`是以太坊虚拟机(`EVM`)智能合约的语言。同时,我认为`solidity`是玩链上项目必备的技能:区块链项目大部分是开源的,如果你能读懂代码,就可以规避很多亏钱项目。
## Solidity 简介

`Solidity`具有两个特点:
`Solidity` 是一种用于编写以太坊虚拟机(`EVM`)智能合约的编程语言。我认为掌握 `Solidity` 是参与链上项目的必备技能:区块链项目大部分是开源的,如果你能读懂代码,就可以规避很多亏钱项目。

1. 基于对象:学会之后,能帮你挣钱找对象。
2. 高级:不会`solidity`,在币圈显得很low。
`Solidity` 具有两个特点:

## 开发工具:remix
本教程中,我会用`remix`来跑`solidity`合约。`remix`是以太坊官方推荐的智能合约开发IDE(集成开发环境),适合新手,可以在浏览器中快速部署测试智能合约,你不需要在本地安装任何程序。
1. "基于对象":学会 `Solidity` 之后,可以助你在区块链领域找到好工作,挣钱找对象。
2. "高级":不会 `Solidity`,在币圈会显得很 low。

## 开发工具:Remix

本教程中,我们将使用 `Remix` 运行 `Solidity` 合约。`Remix` 是以太坊官方推荐的智能合约集成开发环境(IDE),适合新手,在浏览器中快速部署和测试智能合约,无需在本地安装任何程序。

网址:[remix.ethereum.org](https://remix.ethereum.org)

进入`remix`,我们可以看到最左边的菜单有三个按钮,分别对应文件(写代码的地方),编译(跑代码),部署(部署到链上)。我们点新建(`Create New File`)按钮,就可以创建一个空白的`solidity`合约。
`Remix` 中,左侧菜单有三个按钮,分别对应文件(编写代码)、编译(运行代码)和部署(将合约部署到链上)。点击“创建新文件”(`Create New File`)按钮,即可创建一个空白的 `Solidity` 合约。

![Remix 面板](./img/1-1.png)

![remix面板](./img/1-1.png)
## 第一个 Solidity 程序

这个简单的程序只有 1 行注释和 3 行代码:

## 第一个Solidity程序
很简单,只有1行注释+3行代码:
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract HelloWeb3{
string public _string = "Hello Web3!";
}
```
我们拆开分析,学习solidity代码源文件的结构:
1. 第1行是注释,会写一下这个代码所用的软件许可(license),这里用的是MIT license。如果不写许可,编译时会警告(warning),但程序可以运行。solidity的注释由“//”开头,后面跟注释的内容(不会被程序运行)。
```solidity
// SPDX-License-Identifier: MIT
```
2. 第2行声明源文件所用的solidity版本,因为不同版本语法有差别。这行代码意思是源文件将不允许小于 0.8.4 版本或大于等于 0.9.0 的编译器编译(第二个条件由`^`提供)。Solidity 语句以分号(;)结尾。
```solidity
pragma solidity ^0.8.4;
```

我们拆解程序,学习 Solidity 代码源文件的结构:

1. 第 1 行是注释,说明代码所使用的软件许可(license),这里使用的是 MIT 许可。如果不写许可,编译时会出现警告(warning),但程序仍可运行。Solidity 注释以“//”开头,后面跟注释内容,注释不会被程序执行。

```solidity
// SPDX-License-Identifier: MIT
```

2. 第 2 行声明源文件所使用的 Solidity 版本,因为不同版本的语法有差异。这行代码表示源文件将不允许小于 0.8.4 版本或大于等于 0.9.0 的编译器编译(第二个条件由 `^` 提供)。Solidity 语句以分号(;)结尾。
```solidity
pragma solidity ^0.8.4;
```

3. 第3-4行是合约部分,第3行创建合约(contract),并声明合约的名字 HelloWeb3。第4行是合约的内容,我们声明了一个string(字符串)变量_string,并给他赋值 “Hello Web3!”。
```solidity
contract HelloWeb3{
string public _string = "Hello Web3!";
}
```
以后我们会更细的介绍solidity中的变量。
3. 第 3-4 行是合约部分。第 3 行创建合约(contract),并声明合约名为 `HelloWeb3`。第 4 行是合约内容,声明了一个 string(字符串)变量 `_string`,并赋值为 "Hello Web3!"。

```solidity
contract HelloWeb3 {
string public _string = "Hello Web3!";
}
```

后续我们会更详细地介绍 Solidity 中的变量。

## 编译并部署代码
在编辑代码的页面,按ctrl+S就可以编译代码,非常方便。

编译好之后,点击左侧菜单的“部署”按钮,进入部署页面。
在 Remix 编辑代码的页面,按 Ctrl + S 即可编译代码,非常方便。

编译完成后,点击左侧菜单的“部署”按钮,进入部署页面。

![](./img/1-2.png)

在默认情况下,remix会用Remix虚拟机 (之前被称为JavaScript虚拟机) 来模拟以太坊链,运行智能合约,类似在浏览器里跑一条测试链。并且remix会分配几个测试账户给你,每个里面有100 ETH(测试代币),可劲儿用。你点Deploy(黄色按钮),就可以部署咱们写好的合约了
默认情况下,`Remix` 会使用 `Remix` 虚拟机(以前称为 JavaScript 虚拟机)来模拟以太坊链,运行智能合约,类似在浏览器里运行一条测试链。`Remix` 还会为你分配一些测试账户,每个账户里有 100 ETH(测试代币),随意使用。点击 `Deploy`(黄色按钮),即可部署我们编写的合约

![](./img/1-3.png)

部署成功后,你会在下面看到名为`HelloWeb3`的合约,点击`_string`就能看到我们代码中写的 “Hello Web3!” 了
部署成功后,在下方会看到名为 `HelloWeb3` 的合约。点击 `_string`即可看到 "Hello Web3!"

## 总结
这一讲,我们简单介绍了`solidity``remix`工具,并完成了第一个`solidity`程序--`HelloWeb3`下面我们将继续`solidity`旅程
本节课程中,我们简要介绍了 `Solidity``Remix` 工具,并完成了第一个 `Solidity` 程序 —— `HelloWeb3`接下来,我们将继续深入学习 `Solidity`

### 中文solidity资料推荐:
1. [Solidity中文文档](https://solidity-cn.readthedocs.io/zh/develop/introduction-to-smart-contracts.html)(官方文档的中文翻译)
Expand Down
12 changes: 5 additions & 7 deletions 02_ValueTypes/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ tags:
- `==` (等于)
- `!=` (不等于)

代码:
```solidity
// 布尔运算
bool public _bool1 = !_bool; //取非
Expand All @@ -69,7 +68,6 @@ tags:
- 比较运算符(返回布尔值): `<=``<``==``!=``>=``>`
- 算数运算符: `+``-``*``/``%`(取余),`**`(幂)

代码:
```solidity
// 整数运算
uint256 public _number1 = _number + 1; // +,-,*,/
Expand All @@ -86,7 +84,6 @@ tags:

我们会在之后的章节更加详细的介绍地址类型。

代码
```solidity
// 地址
address public _address = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
Expand All @@ -96,17 +93,18 @@ tags:
```

### 4. 定长字节数组
字节数组`bytes`分两种:

- 定长: 属于数值类型,根据每个元素存储数据的大小分为 `bytes1`, `bytes8`, `bytes32` 等类型,每个元素最多存储 32 bytes数据。数组长度在声明之后不能改变。
- 不定长: 属于引用类型,数组长度在声明之后可以改变,包括 `bytes` 等,之后的章节会详细介绍。
字节数组 `bytes` 分为定长和不定长两种:

- 定长字节数组: 属于数值类型,数组长度在声明之后不能改变。根据每个元素存储数据的大小分为 `bytes1`, `bytes8`, `bytes32` 等类型,每个元素最多存储 32 bytes数据。
- 不定长字节数组: 属于引用类型(之后的章节介绍),数组长度在声明之后可以改变,包括 `bytes` 等。

代码:
```solidity
// 固定长度的字节数组
bytes32 public _byte32 = "MiniSolidity";
bytes1 public _byte = _byte32[0];
```

上面代码中,`MiniSolidity`变量以字节的方式存储进变量`_byte32`。如果把它转换成`16进制`为,就是:`0x4d696e69536f6c69646974790000000000000000000000000000000000000000`

`_byte`变量的值为`_byte32`的第一个字节,即`0x4d`
Expand Down
6 changes: 3 additions & 3 deletions 12_Event/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ event Transfer(address indexed from, address indexed to, uint256 value);

![](img/12-3.png)

### 主题 `Topics`
### 主题 `topics`

日志的第一部分是主题数组,用于描述事件,长度不能超过`4`。它的第一个元素是事件的签名(哈希)。对于上面的`Transfer`事件,它的签名就是:
```solidity
Expand All @@ -72,9 +72,9 @@ keccak256("Transfer(addrses,address,uint256)")

`indexed`标记的参数可以理解为检索事件的索引“键”,方便之后搜索。每个 `indexed` 参数的大小为固定的256比特,如果参数太大了(比如字符串),就会自动计算哈希存储在主题中。

### 数据 `Data`
### 数据 `data`

事件中不带 `indexed`的参数会被存储在 `data` 部分中,可以理解为事件的“值”。`data` 部分的变量不能被直接检索,但可以存储任意大小的数据。因此一般 `data` 部分可以用来存储复杂的数据结构,例如数组和字符串等等,因为这些数据超过了256比特,即使存储在事件的 `topic` 部分中,也是以哈希的方式存储。另外,`data` 部分的变量在存储上消耗的gas相比于 `topic` 更少。
事件中不带 `indexed`的参数会被存储在 `data` 部分中,可以理解为事件的“值”。`data` 部分的变量不能被直接检索,但可以存储任意大小的数据。因此一般 `data` 部分可以用来存储复杂的数据结构,例如数组和字符串等等,因为这些数据超过了256比特,即使存储在事件的 `topics` 部分中,也是以哈希的方式存储。另外,`data` 部分的变量在存储上消耗的gas相比于 `topics` 更少。

## `Remix`演示
`Event.sol` 合约为例,编译部署。
Expand Down
23 changes: 12 additions & 11 deletions 17_Library/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ tags:
所有代码和教程开源在github: [github.com/AmazingAng/WTFSolidity](https://github.com/AmazingAng/WTFSolidity)

-----
这一讲,我们用`ERC721`的引用的库合约`String`为例介绍`solidity`中的库合约(`library`),并总结了常用的库函数
这一讲,我们用`ERC721`的引用的库合约`String`为例介绍`solidity`中的库合约(`library`),并总结了常用的库合约

## 库函数
库函数是一种特殊的合约,为了提升`solidity`代码的复用性和减少`gas`而存在。库合约一般都是一些好用的函数合集(`库函数`),由大神或者项目方创作,咱们站在巨人的肩膀上,会用就行了。
## 库合约

库合约是一种特殊的合约,为了提升`solidity`代码的复用性和减少`gas`而存在。库合约是一系列的函数合集,由大神或者项目方创作,咱们站在巨人的肩膀上,会用就行了。


![库合约:站在巨人的肩膀上](https://images.mirror-media.xyz/publication-images/HJC0UjkALdrL8a2BmAE2J.jpeg?height=300&width=388)
Expand Down Expand Up @@ -100,34 +101,34 @@ library Strings {
他主要包含两个函数,`toString()``uint256`转为`string``toHexString()``uint256`转换为`16进制`,在转换为`string`

### 如何使用库合约
我们用String库函数的toHexString()来演示两种使用库合约中函数的办法。
我们用String库合约的toHexString()来演示两种使用库合约中函数的办法。

**1. 利用using for指令**

指令`using A for B;`可用于附加库函数(从库 A)到任何类型(B)。添加完指令后,库`A`中的函数会自动添加为`B`类型变量的成员,可以直接调用。注意:在调用的时候,这个变量会被当作第一个参数传递给函数:
指令`using A for B;`可用于附加库合约(从库 A)到任何类型(B)。添加完指令后,库`A`中的函数会自动添加为`B`类型变量的成员,可以直接调用。注意:在调用的时候,这个变量会被当作第一个参数传递给函数:
```solidity
// 利用using for指令
using Strings for uint256;
function getString1(uint256 _number) public pure returns(string memory){
// 库函数会自动添加为uint256型变量的成员
// 库合约中的函数会自动添加为uint256型变量的成员
return _number.toHexString();
}
```
**2. 通过库合约名称调用库函数**
**2. 通过库合约名称调用函数**
```solidity
// 直接通过库合约名调用
function getString2(uint256 _number) public pure returns(string memory){
return Strings.toHexString(_number);
}
```
我们部署合约并输入`170`测试一下,两种方法均能返回正确的`16进制string` “0xaa”。证明我们调用库函数成功
我们部署合约并输入`170`测试一下,两种方法均能返回正确的`16进制string` “0xaa”。证明我们调用库合约成功


![成功调用库函数](https://images.mirror-media.xyz/publication-images/bzB_JDC9f5VWHRjsjQyQa.png?height=750&width=580)
![成功调用库合约](https://images.mirror-media.xyz/publication-images/bzB_JDC9f5VWHRjsjQyQa.png?height=750&width=580)
## 总结
这一讲,我们用`ERC721`的引用的库函数`String`为例介绍`solidity`中的库函数`Library`)。99%的开发者都不需要自己去写库合约,会用大神写的就可以了。我们只需要知道什么情况该用什么库合约。常用的有:
这一讲,我们用`ERC721`的引用的库合约`String`为例介绍`solidity`中的库合约`Library`)。99%的开发者都不需要自己去写库合约,会用大神写的就可以了。我们只需要知道什么情况该用什么库合约。常用的有:

1. [String](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/Strings.sol):将`uint256`转换为`String`
2. [Address](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/Address.sol):判断某个地址是否为合约地址
3. [Create2](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/Create2.sol):更安全的使用`Create2 EVM opcode`
4. [Arrays](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/Arrays.sol)跟数组相关的库函数
4. [Arrays](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/Arrays.sol)跟数组相关的库合约
4 changes: 2 additions & 2 deletions 24_Create/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ tags:

-----

在以太坊链上,用户(外部账户,`EOA`)可以创建智能合约,智能合约同样也可以创建新的智能合约。去中心化交易所`uniswap`就是利用工厂合约(`Factory`)创建了无数个币对合约(`Pair`)。这一讲,我会用简化版的`uniswap`讲如何通过合约创建合约。
在以太坊链上,用户(外部账户,`EOA`)可以创建智能合约,智能合约同样也可以创建新的智能合约。去中心化交易所`uniswap`就是利用工厂合约(`PairFactory`)创建了无数个币对合约(`Pair`)。这一讲,我会用简化版的`uniswap`讲如何通过合约创建合约。

## `create``create2`
## `create`
有两种方法可以在合约中创建新合约,`create``create2`,这里我们讲`create`,下一讲会介绍`create2`

`create`的用法很简单,就是`new`一个合约,并传入新合约构造函数所需的参数:
Expand Down

0 comments on commit 6ae3920

Please sign in to comment.