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 67c0843 + d8b8bed commit ceb863d
Show file tree
Hide file tree
Showing 68 changed files with 483 additions and 230 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
6 changes: 3 additions & 3 deletions 03_Function/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Solidity语言的函数非常灵活,可以进行各种复杂操作。在本教
我们先看一下 Solidity 中函数的形式:

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

Expand All @@ -36,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 @@ -47,7 +47,7 @@ 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` 的介绍见下一节。

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 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
55 changes: 30 additions & 25 deletions 22_Call/Call.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,61 @@
pragma solidity ^0.8.21;

contract OtherContract {
uint256 private _x = 0; // 状態変数_x
// ethを受け取るイベント、amountとgasを記録
uint256 private _x = 0; // 状态变量x
// 收到eth事件,记录amount和gas
event Log(uint amount, uint gas);

event Log(uint256 amount, uint256 gas);
fallback() external payable{}

fallback() external payable {}

// コントラクトのETH残高を返す関数
function getBalance() public view returns (uint256) {
// 返回合约ETH余额
function getBalance() view public returns(uint) {
return address(this).balance;
}

// _xの値を設定できる関数。同時にコントラクトへETHを送信することもできる(payable)
function setX(uint256 x) external payable {
// 可以调整状态变量_x的函数,并且可以往合约转ETH (payable)
function setX(uint256 x) external payable{
_x = x;
// もしETHの送信がある場合のみLogイベントを放出
if (msg.value > 0) {
// 如果转入ETH,则释放Log事件
if(msg.value > 0){
emit Log(msg.value, gasleft());
}
}

// xの値を取得する関数
function getX() external view returns (uint256 x) {
// 读取x
function getX() external view returns(uint x){
x = _x;
}
}

contract Call {
// Response イベントは`call`の結果`success`と`data`を出力します
contract Call{
// 定义Response事件,输出call返回的结果success和data
event Response(bool success, bytes data);

function callSetX(address payable _addr, uint256 x) public payable {
// setX()をcallし、ETHを送信
(bool success, bytes memory data) = _addr.call{value: msg.value}(abi.encodeWithSignature("setX(uint256)", x));
// call setX(),同时可以发送ETH
(bool success, bytes memory data) = _addr.call{value: msg.value}(
abi.encodeWithSignature("setX(uint256)", x)
);

emit Response(success, data); // イベントを放出
emit Response(success, data); //释放事件
}

function callGetX(address _addr) external returns (uint256) {
function callGetX(address _addr) external returns(uint256){
// call getX()
(bool success, bytes memory data) = _addr.call(abi.encodeWithSignature("getX()"));
(bool success, bytes memory data) = _addr.call(
abi.encodeWithSignature("getX()")
);

emit Response(success, data); // イベントを放出
emit Response(success, data); //释放事件
return abi.decode(data, (uint256));
}

function callNonExist(address _addr) external {
// 存在しない関数を呼び出す
(bool success, bytes memory data) = _addr.call(abi.encodeWithSignature("foo(uint256)"));
function callNonExist(address _addr) external{
// call 不存在的函数
(bool success, bytes memory data) = _addr.call(
abi.encodeWithSignature("foo(uint256)")
);

emit Response(success, data); // イベントを放出
emit Response(success, data); //释放事件
}
}
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`
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
6 changes: 3 additions & 3 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 Expand Up @@ -590,7 +590,7 @@ interface ERC721Metadata /* is ERC721 */ {
IERC721Metadata.name.selector ^ IERC721Metadata.symbol.selector ^ IERC721Metadata.tokenURI.selector
```

solamte实现的ERC721.sol是怎么完成这些ERC165要求的特性的呢?
solmate实现的ERC721.sol是怎么完成这些ERC165要求的特性的呢?

```solidity
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
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 ceb863d

Please sign in to comment.