Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
AmazingAng authored Oct 19, 2024
2 parents 2af028e + 2c467c2 commit 8b4a4b7
Show file tree
Hide file tree
Showing 72 changed files with 443 additions and 182 deletions.
12 changes: 6 additions & 6 deletions 02_ValueTypes/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ bool public _bool5 = _bool != _bool1; // 不相等
```solidity
// 整型
int public _int = -1; // 整数,包括负数
uint public _uint = 1; // 正整数
uint256 public _number = 20220330; // 256位正整数
uint public _uint = 1; // 无符号整数
uint256 public _number = 20220330; // 256位无符号整数
```

常用的整型运算符包括:

- 比较运算符(返回布尔值): `<=``<``==``!=``>=``>`
- 算数运算符`+``-``*``/``%`(取余),`**`(幂)
- 算术运算符`+``-``*``/``%`(取余),`**`(幂)

```solidity
// 整数运算
Expand Down Expand Up @@ -117,7 +117,7 @@ bytes32 public _byte32 = "MiniSolidity";
bytes1 public _byte = _byte32[0];
```

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

`_byte` 变量的值为 `_byte32` 的第一个字节,即 `0x4d`

Expand All @@ -132,7 +132,7 @@ enum ActionSet { Buy, Hold, Sell }
ActionSet action = ActionSet.Buy;
```

枚举可以显式地和 `uint` 相互转换,并会检查转换的正整数是否在枚举的长度内,否则会报错:
枚举可以显式地和 `uint` 相互转换,并会检查转换的无符号整数是否在枚举的长度内,否则会报错:

```solidity
// enum可以和uint显式的转换
Expand All @@ -141,7 +141,7 @@ function enumToUint() external view returns(uint){
}
```

`enum` 是一个比较冷门的变量,几乎没什么人用。
`enum` 是一个比较冷门的数据类型,几乎没什么人用。

## 在 Remix 上运行

Expand Down
15 changes: 11 additions & 4 deletions 03_Function/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ Solidity语言的函数非常灵活,可以进行各种复杂操作。在本教
我们先看一下 Solidity 中函数的形式:

```solidity
function <function name>(<parameter types>) {internal|external|public|private} [pure|view|payable] [returns (<return types>)]
function <function name>([parameter types[, ...]]) {internal|external|public|private} [pure|view|payable] [virtual|override] [<modifiers>]
[returns (<return types>)]{ <function body> }
```

看着有一些复杂,让我们从前往后逐个解释(方括号中的是可写可不
Expand All @@ -35,7 +36,7 @@ function <function name>(<parameter types>) {internal|external|public|private} [

2. `<function name>`:函数名。

3. `(<parameter types>)`:圆括号内写入函数的参数,即输入到函数的变量类型和名称。
3. `([parameter types[, ...]])`:圆括号内写入函数的参数,即输入到函数的变量类型和名称。

4. `{internal|external|public|private}`:函数可见性说明符,共有4种。

Expand All @@ -46,11 +47,17 @@ function <function name>(<parameter types>) {internal|external|public|private} [

**注意 1**:合约中定义的函数需要明确指定可见性,它们没有默认值。

**注意 2**`public|private|internal` 也可用于修饰状态变量。`public`变量会自动生成同名的`getter`函数,用于查询数值。未标明可见性类型的状态变量,默认为`internal`
**注意 2**`public|private|internal` 也可用于修饰状态变量(定义可参考[WTF Solidity 第5讲的相关内容]([../05_DataStorage/readme.md#1-状态变量](https://github.com/AmazingAng/WTF-Solidity/tree/main/05_DataStorage#1-%E7%8A%B6%E6%80%81%E5%8F%98%E9%87%8F)))`public`变量会自动生成同名的`getter`函数,用于查询数值。未标明可见性类型的状态变量,默认为`internal`

5. `[pure|view|payable]`:决定函数权限/功能的关键字。`payable`(可支付的)很好理解,带着它的函数,运行的时候可以给合约转入 ETH。`pure``view` 的介绍见下一节。

6. `[returns ()]`:函数返回的变量类型和名称。
6. `[virtual|override]`: 方法是否可以被重写,或者是否是重写方法。`virtual`用在父合约上,标识的方法可以被子合约重写。`override`用在自合约上,表名方法重写了父合约的方法。

7. `<modifiers>`: 自定义的修饰器,可以有0个或多个修饰器。

8. `[returns ()]`:函数返回的变量类型和名称。

9. `<function body>`: 函数体。

## 到底什么是 `Pure``View`

Expand Down
2 changes: 1 addition & 1 deletion 04_Return/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function returnMultiple() public pure returns(uint256, bool, uint256[3] memory){

## 命名式返回

我们可以在 `returns` 中标明返回变量的名称。Solidity 会初始化这些变量,并且自动返回这些函数的值,无需使用 `return`
我们可以在 `returns` 中标明返回变量的名称。Solidity 会初始化这些变量,并且自动返回这些变量的值,无需使用 `return`

```solidity
// 命名式返回
Expand Down
2 changes: 1 addition & 1 deletion 05_DataStorage/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function global() external view returns(address, uint, bytes memory){

在上面例子里,我们使用了3个常用的全局变量:`msg.sender``block.number``msg.data`,他们分别代表请求发起地址,当前区块高度,和请求数据。下面是一些常用的全局变量,更完整的列表请看这个[链接](https://learnblockchain.cn/docs/solidity/units-and-global-variables.html#special-variables-and-functions)

- `blockhash(uint blockNumber)`: (`bytes32`) 给定区块的哈希值 – 只适用于256最近区块, 不包含当前区块。
- `blockhash(uint blockNumber)`: (`bytes32`) 给定区块的哈希值 – 只适用于最近的256个区块, 不包含当前区块。
- `block.coinbase`: (`address payable`) 当前区块矿工的地址
- `block.gaslimit`: (`uint`) 当前区块的gaslimit
- `block.number`: (`uint`) 当前区块的number
Expand Down
2 changes: 1 addition & 1 deletion 07_Mapping/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ mapping(address => address) public swapPair; // 币对的映射,地址到地

- **原理1**: 映射不储存任何键(`Key`)的资讯,也没有length的资讯。

- **原理2**: 映射使用`keccak256(abi.encodePacked(key, slot))`当成offset存取value,其中`slot`是映射变量定义所在的插槽位置。
- **原理2**: 对于映射使用`keccak256(h(key) . slot)`计算存取value的位置。感兴趣的可以去阅读 [WTF Solidity 内部规则: 映射存储布局](https://github.com/WTFAcademy/WTF-Solidity-Internals/tree/master/tutorials/02_MappingStorage)

- **原理3**: 因为Ethereum会定义所有未使用的空间为0,所以未赋值(`Value`)的键(`Key`)初始值都是各个type的默认值,如uint的默认值是0。

Expand Down
2 changes: 1 addition & 1 deletion 09_Constant/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ address constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000;

### immutable

`immutable`变量可以在声明时或构造函数中初始化,因此更加灵活。在`Solidity v8.0.21`以后,`immutable`变量不需要显式初始化,未显式初始化的`immutable`变量将使用数值类型的初始值(见 [8. 变量初始值](https://github.com/AmazingAng/WTF-Solidity/blob/main/08_InitialValue/readme.md#%E5%8F%98%E9%87%8F%E5%88%9D%E5%A7%8B%E5%80%BC))。反之,则需要显式初始化。
`immutable`变量可以在声明时或构造函数中初始化,因此更加灵活。在`Solidity v0.8.21`以后,`immutable`变量不需要显式初始化,未显式初始化的`immutable`变量将使用数值类型的初始值(见 [8. 变量初始值](https://github.com/AmazingAng/WTF-Solidity/blob/main/08_InitialValue/readme.md#%E5%8F%98%E9%87%8F%E5%88%9D%E5%A7%8B%E5%80%BC))。反之,则需要显式初始化。
`immutable`变量既在声明时初始化,又在constructor中初始化,会使用constructor初始化的值。

``` solidity
Expand Down
2 changes: 1 addition & 1 deletion 10_InsertionSort/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ Remix decoded output 出现错误内容

### 正确的Solidity插入排序

花了几个小时,在`Dapp-Learning`社群一个朋友的帮助下,终于找到了`bug`所在。`Solidity`中最常用的变量类型是`uint`也就是正整数,取到负值的话,会报`underflow`错误。而在插入算法中,变量`j`有可能会取到`-1`,引起报错。
花了几个小时,在`Dapp-Learning`社群一个朋友的帮助下,终于找到了`bug`所在。`Solidity`中最常用的变量类型是`uint`也就是无符号整数,取到负值的话,会报`underflow`错误。而在插入算法中,变量`j`有可能会取到`-1`,引起报错。

这里,我们需要把`j`加1,让它无法取到负值。正确代码:

Expand Down
2 changes: 1 addition & 1 deletion 13_Inheritance/Inheritance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pragma solidity ^0.8.21;
contract Yeye {
event Log(string msg);

// 定义3个function: hip(), pop(), man(),Log值为Yeye。
// 定义3个function: hip(), pop(), yeye(),Log值为Yeye。
function hip() public virtual{
emit Log("Yeye");
}
Expand Down
2 changes: 1 addition & 1 deletion 13_Inheritance/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ mapping(address => uint256) public override balanceOf;
contract Yeye {
event Log(string msg);
// 定义3个function: hip(), pop(), man(),Log值为Yeye。
// 定义3个function: hip(), pop(), yeye(),Log值为Yeye。
function hip() public virtual{
emit Log("Yeye");
}
Expand Down
4 changes: 2 additions & 2 deletions 17_Library/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ tags:
3. 不能接收以太币
4. 不可以被销毁

需要注意的是,库合约重的函数可见性如果被设置为`public`或者`external`,则在调用函数时会触发一次`delegatecall`。而如果被设置为`internal`,则不会引起。对于设置为`private`可见性的函数来说,其仅能在库合约中可见,在其他合约中不可用。
需要注意的是,库合约中的函数可见性如果被设置为`public`或者`external`,则在调用函数时会触发一次`delegatecall`。而如果被设置为`internal`,则不会引起。对于设置为`private`可见性的函数来说,其仅能在库合约中可见,在其他合约中不可用。


## Strings库合约
Expand Down Expand Up @@ -103,7 +103,7 @@ library Strings {
}
```

他主要包含两个函数`toString()``uint256`转为`string``toHexString()``uint256`转换为`16进制`,在转换为`string`
它主要包含两个函数`toString()``uint256`转换为10进制的`string``toHexString()``uint256`转换为16进制的`string`

### 如何使用库合约

Expand Down
3 changes: 2 additions & 1 deletion 23_Delegatecall/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ contract C {

### 发起调用的合约B

首先,合约`B`必须和目标合约`C`的变量存储布局必须相同,两个变量,并且顺序为`num``sender`
首先,合约`B`必须和目标合约`C`的变量存储布局必须相同 —— 即存在两个 `public` 变量且变量类型顺序为 `uint256``address`
> **注意:** 变量名称可以不同
```solidity
contract B {
Expand Down
Binary file added 24_Create/img/24-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions 24_Create/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ contract PairFactory{
}
```

工厂合约(`PairFactory`)有两个状态变量`getPair`是两个代币地址到币对地址的`map`,方便根据代币找到币对地址;`allPairs`是币对地址的数组,存储了所有代币地址
工厂合约(`PairFactory`)有两个状态变量`getPair`是两个代币地址到币对地址的`map`,方便根据代币找到币对地址;`allPairs`是币对地址的数组,存储了所有币对地址

`PairFactory`合约只有一个`createPair`函数,根据输入的两个代币地址`tokenA``tokenB`来创建新的`Pair`合约。其中

Expand All @@ -112,13 +112,19 @@ BSC链上的PEOPLE地址: 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
1. 使用`WBNB``PEOPLE`的地址作为参数调用`createPair`,得到`Pair`合约地址:0xD3e2008b4Da2cD6DEAF73471590fF30C86778A48

![24-1](./img/24-1.png)
2. 查看`Pair`合约变量

2. 将 Contract 改为 `Pair`,然后在 At Address 输入框输入 `Pair` 合约地址,创建一个前端接口用于调用已部署的合约。

![24-4](./img/24-4.png)

3. 查看`Pair`合约变量

![24-2](./img/24-2.png)
3. Debug查看`create`操作码

4. Debug查看`create`操作码

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

## 总结

这一讲,我们用极简`Uniswap`的例子介绍了如何使用`create`方法再合约里创建合约,下一讲我们将介绍如何使用`create2`方法来实现极简`Uniswap`
这一讲,我们用极简`Uniswap`的例子介绍了如何使用`create`方法在合约里创建合约,下一讲我们将介绍如何使用`create2`方法来实现极简`Uniswap`
2 changes: 1 addition & 1 deletion 26_DeleteContract/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ tags:
`selfdestruct`使用起来非常简单:

```solidity
selfdestruct(_addr)
selfdestruct(_addr);
```

其中`_addr`是接收合约中剩余`ETH`的地址。`_addr` 地址不需要有`receive()``fallback()`也能接收`ETH`
Expand Down
4 changes: 2 additions & 2 deletions 34_ERC721/ERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "./IERC721Metadata.sol";
import "./String.sol";

contract ERC721 is IERC721, IERC721Metadata{
using Strings for uint256; // 使用String库
using Strings for uint256; // 使用Strings库

// Token名称
string public override name;
Expand All @@ -21,7 +21,7 @@ contract ERC721 is IERC721, IERC721Metadata{
mapping(address => uint) private _balances;
// tokenID 到 授权地址 的授权映射
mapping(uint => address) private _tokenApprovals;
// owner地址。到operator地址 的批量授权映射
// owner地址 到 operator地址 的批量授权映射
mapping(address => mapping(address => bool)) private _operatorApprovals;

// 错误 无效的接收者
Expand Down
4 changes: 2 additions & 2 deletions 34_ERC721/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ import "./IERC721Metadata.sol";
import "./String.sol";
contract ERC721 is IERC721, IERC721Metadata{
using Strings for uint256; // 使用String库
using Strings for uint256; // 使用Strings库
// Token名称
string public override name;
Expand All @@ -222,7 +222,7 @@ contract ERC721 is IERC721, IERC721Metadata{
mapping(address => uint) private _balances;
// tokenID 到 授权地址 的授权映射
mapping(uint => address) private _tokenApprovals;
// owner地址。到operator地址 的批量授权映射
// owner地址 到 operator地址 的批量授权映射
mapping(address => mapping(address => bool)) private _operatorApprovals;
// 错误 无效的接收者
Expand Down
8 changes: 4 additions & 4 deletions 35_DutchAuction/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ contract DutchAuction is Ownable, ERC721 {

合约中一共有`9`个状态变量,其中有`6`个和拍卖相关,他们是:

- `COLLECTOIN_SIZE`:NFT总量。
- `COLLECTION_SIZE`:NFT总量。
- `AUCTION_START_PRICE`:荷兰拍卖起拍价,也是最高价。
- `AUCTION_END_PRICE`:荷兰拍卖结束价,也是最低价/地板价。
- `AUCTION_TIME`:拍卖持续时长。
- `AUCTION_DROP_INTERVAL`:每过多久时间,价格衰减一次。
- `auctionStartTime`:拍卖起始时间(区块链时间戳,`block.timestamp`)。

```solidity
uint256 public constant COLLECTOIN_SIZE = 10000; // NFT总数
uint256 public constant COLLECTION_SIZE = 10000; // NFT总数
uint256 public constant AUCTION_START_PRICE = 1 ether; // 起拍价(最高价)
uint256 public constant AUCTION_END_PRICE = 0.1 ether; // 结束价(最低价/地板价)
uint256 public constant AUCTION_TIME = 10 minutes; // 拍卖时间,为了测试方便设为10分钟
Expand All @@ -82,7 +82,7 @@ contract DutchAuction is Ownable, ERC721 {
- 设定拍卖起始时间:我们在构造函数中会声明当前区块时间为起始时间,项目方也可以通过`setAuctionStartTime()`函数来调整:

```solidity
constructor() ERC721("WTF Dutch Auctoin", "WTF Dutch Auctoin") {
constructor() ERC721("WTF Dutch Auction", "WTF Dutch Auction") {
auctionStartTime = block.timestamp;
}
Expand Down Expand Up @@ -132,7 +132,7 @@ contract DutchAuction is Ownable, ERC721 {
"sale has not started yet"
); // 检查是否设置起拍时间,拍卖是否开始
require(
totalSupply() + quantity <= COLLECTOIN_SIZE,
totalSupply() + quantity <= COLLECTION_SIZE,
"not enough remaining reserved for auction to support desired mint amount"
); // 检查是否超过NFT上限
Expand Down
12 changes: 7 additions & 5 deletions 38_NFTSwap/NFTSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ contract NFTSwap is IERC721Receiver {
require(_nft.getApproved(_tokenId) == address(this), "Need Approval"); // 合约得到授权
require(_price > 0); // 价格大于0

Order storage _order = nftList[_nftAddr][_tokenId]; //设置NF持有人和价格
Order storage _order = nftList[_nftAddr][_tokenId]; //设置NFT持有人和价格
_order.owner = msg.sender;
_order.price = _price;
// 将NFT转账到合约
Expand All @@ -68,13 +68,15 @@ contract NFTSwap is IERC721Receiver {
// 将NFT转给买家
_nft.safeTransferFrom(address(this), msg.sender, _tokenId);
// 将ETH转给卖家,多余ETH给买家退款
payable(_order.owner).transfer(_order.price);
payable(msg.sender).transfer(msg.value - _order.price);

delete nftList[_nftAddr][_tokenId]; // 删除order
if (msg.value > _order.price) {
payable(_order.owner).transfer(_order.price);
payable(msg.sender).transfer(msg.value - _order.price);
}

// 释放Purchase事件
emit Purchase(msg.sender, _nftAddr, _tokenId, _order.price);

delete nftList[_nftAddr][_tokenId]; // 删除order
}

// 撤单: 卖家取消挂单
Expand Down
Loading

0 comments on commit 8b4a4b7

Please sign in to comment.