Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
buttonwild authored Sep 29, 2024
2 parents 45ad3ab + d781c86 commit 65d1460
Show file tree
Hide file tree
Showing 128 changed files with 10,139 additions and 991 deletions.
2 changes: 2 additions & 0 deletions 0x3f3f3f3f3f3f.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ timezone: Asia/Taipei
2. 繼承的寫法蠻特別的要注意繼承的輩份關係由左到右由大到小,super可以用來調用最近的父合約,重載父合約的函數要用overrider關鍵字,然後如果父合約希望讓子合約重載他的函數他要加上virtual不然子合約是無法重載的,假如重載的函數在多個父輩都存在則要把父輩都打出來在override後面
3. 知道了interface的用法以及要怎麼跟別人部署好的合約互動 如果是符合特定IERC可以直接import來用不用自己手打interface 如果不是那你可以去etherscan裡面看他的abi在按照他提供的內容打出他的interface
4. 理解了異常的差別,之前只用過require 學了才知道require是gas消耗量最高的 然後error感覺跟require很像,只是把revert的部分分開來寫但是他的gas消耗量是最小的
### 2024.09.29
今天的學習內容主要是在delegate call上面,delegatecall是讓呼叫合約可以在自己的上下文執行被呼叫合約的函數,那有個問題是,這樣呼叫合約不就要有跟被呼叫合約一樣的狀態變量以及名稱,事實上delegatecall的用法中他辨認的是slot的位置,例如你在被呼叫合約裡面作用的是slot1,他就會作用在呼叫合約裡面的slot1,這意味的如果呼叫合約的slot沒有跟被呼叫合約的slot對齊就可能會發生嚴重的錯誤

<!-- Content_END -->

17 changes: 16 additions & 1 deletion 0xRory.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,22 @@ timezone: Asia/Taipei

### 2024.09.26

day03:
day04:
[WTF Academy Solidity 101 7-11 Note](/content/0xRory/104.md)

### 2024.09.27

day05:
[WTF Academy Solidity 101 12 Note](/content/0xRory/105.md)

### 2024.09.28

day06:
[WTF Academy Solidity 101 13 Note](/content/0xRory/106.md)

### 2024.09.29

day07:
[WTF Academy Solidity 101 14 Note](/content/0xRory/107.md)

<!-- Content_END -->
63 changes: 62 additions & 1 deletion 0xfu.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ NFT 合约时可以通过继承 ERC721 合约从而快速高效的进行业务
###



### 2024.09.27

#### 荷兰拍
Expand Down Expand Up @@ -276,4 +275,66 @@ contract BeraApDutchAuction is Ownable, ERC721 {

###



### 2024.09.28

提交被覆盖,待补充

###


### 2024.09.29

#### 数字签名

以太坊使用的数字签名算法叫双椭圆曲线数字签名算法(ECDSA),基于双椭圆曲线“私钥-公钥”对的数字签名算法。

ECDSA:
- 公钥
- 私钥


NFT项目方可以利用ECDSA的验证特性发放白名单,而且签名是线下的不需要Gas,经济又方便。

```Solidity
contract SignatureNFT is ERC721 {
address immutable public signer; // 签名地址
mapping(address => bool) public mintedAddress; // 记录已经mint的地址
// 构造函数,初始化NFT合集的名称、代号、签名地址
constructor(string memory _name, string memory _symbol, address _signer)
ERC721(_name, _symbol)
{
signer = _signer;
}
// 利用ECDSA验证签名并mint
function mint(address _account, uint256 _tokenId, bytes memory _signature)
external
{
bytes32 _msgHash = getMessageHash(_account, _tokenId); // 将_account和_tokenId打包消息
bytes32 _ethSignedMessageHash = ECDSA.toEthSignedMessageHash(_msgHash); // 计算以太坊签名消息
require(verify(_ethSignedMessageHash, _signature), "Invalid signature"); // ECDSA检验通过
require(!mintedAddress[_account], "Already minted!"); // 地址没有mint过
mintedAddress[_account] = true; // 记录mint过的地址, 防止重入攻击
_mint(_account, _tokenId); // mint
}
function getMessageHash(address _account, uint256 _tokenId) public pure returns(bytes32){
return keccak256(abi.encodePacked(_account, _tokenId));
}
function verify(bytes32 _msgHash, bytes memory _signature) public view returns (bool) {
return ECDSA.verify(_msgHash, _signature, signer);
}
}
```

###


<!-- Content_END -->
233 changes: 233 additions & 0 deletions 0xiaoyu.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,4 +394,237 @@ h) 文档和注释:
- 时间单位(如 seconds, minutes, hours)使得在合约中处理时间相关的逻辑时更加清晰和易于理解,减少了因手动计算时间而可能产生的错误。


### 2024.09.27

學習內容:

- [solidity-101 第六课 引用类型](https://www.wtf.academy/docs/solidity-101/ArrayAndStruct/)

笔记

#### 1. 数组(Array)

- 固定长度数组
- 声明格式:T[k](T 为元素类型,k 为长度)
- 例:uint[8] array1;

- 可变长度数组(动态数组)
- 声明格式:T[]
- 例:uint[] array4;
- 特殊情况:bytes 是数组,不需要加 []

- 创建数组规则
- memory 修饰的动态数组需用 new 操作符创建,且长度固定
- 数组字面常数用方括号初始化,类型以第一个元素为准

- 数组成员
- length:数组元素数量
- push():动态数组末尾添加元素
- pop():移除动态数组最后一个元素



#### 2. 结构体(Struct)

定义方法
```
struct Student {
uint256 id;
uint256 score;
}
```

赋值方法
- 在函数中创建 storage 引用
- 直接引用状态变量
- 构造函数式


#### 3. 思考与解答

1. 为什么 Solidity 中区分固定长度和可变长度数组?
这种区分主要是为了优化性能和 gas 消耗。

- 固定长度数组:预先知道大小,可以更高效地分配存储空间,适用于元素数量固定的场景。
- 可变长度数组:灵活性更高,可以动态添加或删除元素,适用于元素数量不确定的场景,但可能消耗更多 gas。


2. bytes 和 byte[] 有什么区别?

- bytes 是动态字节数组,更紧凑,gas 成本更低。
- byte[] 是单字节数组的动态数组,每个元素占用单独的存储槽,gas 成本较高。
- 对于大多数情况,bytes 是更优选择,除非需要修改单个字节。


3. 结构体的不同赋值方法有什么优缺点?

- Storage 引用:可以修改状态变量,但需注意引用的生命周期。
- 直接引用状态变量:简洁直观,但每次赋值都会修改状态变量。
- 构造函数式:一次性初始化所有字段,代码简洁。
- Key-value 方式:可读性好,适合字段较多的结构体。

选择哪种方法取决于具体需求、代码可读性和 gas 优化考虑。



### 2024.09.28

學習內容:

- [solidity-101 第七课 映射类型 mapping](https://www.wtf.academy/docs/solidity-101/Mapping/)

笔记


#### 映射(Mapping)的基本概念
- 通过键(`Key`)查询对应的值(`Value`
- 声明格式:`mapping(_KeyType => _ValueType)`
- 示例:
```solidity
mapping(uint => address) public idToAddress; // id映射到地址
mapping(address => address) public swapPair; // 币对的映射,地址到地址
```

#### 映射的规则
1. `_KeyType` 只能是 Solidity 内置的值类型(如 `uint``address`),不能用自定义结构体
2. 映射的存储位置必须是 `storage`
3. 声明为 `public` 时,Solidity 自动创建 getter 函数
4. 新增键值对语法:`_Var[_Key] = _Value`

#### 映射的原理
1. 不储存键(`Key`)的信息,没有 length 信息
2. 使用 `keccak256(abi.encodePacked(key, slot))` 作为 offset 存取 value
3. 未赋值的键初始值为该类型的默认值(如 uint 默认为 0)

#### 思考与解答
1. 为什么映射的 `_KeyType` 不能使用自定义结构体?
- 这可能是为了确保键的唯一性和哈希计算的效率。内置类型有固定的大小和明确的哈希方法,而自定义结构体可能导致复杂性和不确定性。

2. 映射为什么必须存储在 `storage` 中?
- 映射通常用于存储大量数据和持久化信息。`storage` 是区块链上的永久存储空间,适合存储这种需要长期保存的数据结构。

3. 映射不存储键信息会有什么影响?
- 这意味着我们无法直接获取所有的键或遍历映射。如果需要这些功能,通常需要额外维护一个数组来存储所有的键。


### 2024.09.28

學習內容:

- [solidity-101 第七课 映射类型 mapping](https://www.wtf.academy/docs/solidity-101/Mapping/)

笔记


#### 映射(Mapping)的基本概念
- 通过键(`Key`)查询对应的值(`Value`
- 声明格式:`mapping(_KeyType => _ValueType)`
- 示例:
```solidity
mapping(uint => address) public idToAddress; // id映射到地址
mapping(address => address) public swapPair; // 币对的映射,地址到地址
```

#### 映射的规则
1. `_KeyType` 只能是 Solidity 内置的值类型(如 `uint``address`),不能用自定义结构体
2. 映射的存储位置必须是 `storage`
3. 声明为 `public` 时,Solidity 自动创建 getter 函数
4. 新增键值对语法:`_Var[_Key] = _Value`

#### 映射的原理
1. 不储存键(`Key`)的信息,没有 length 信息
2. 使用 `keccak256(abi.encodePacked(key, slot))` 作为 offset 存取 value
3. 未赋值的键初始值为该类型的默认值(如 uint 默认为 0)

#### 思考与解答
1. 为什么映射的 `_KeyType` 不能使用自定义结构体?
- 这可能是为了确保键的唯一性和哈希计算的效率。内置类型有固定的大小和明确的哈希方法,而自定义结构体可能导致复杂性和不确定性。

2. 映射为什么必须存储在 `storage` 中?
- 映射通常用于存储大量数据和持久化信息。`storage` 是区块链上的永久存储空间,适合存储这种需要长期保存的数据结构。

3. 映射不存储键信息会有什么影响?
- 这意味着我们无法直接获取所有的键或遍历映射。如果需要这些功能,通常需要额外维护一个数组来存储所有的键。



### 2024.09.29

學習內容:

- [solidity-101 第八课 变量初始值](https://www.wtf.academy/docs/solidity-101/InitialValue/)

笔记

#### 值类型初始值
- `boolean`: `false`
- `string`: `""`
- `int`: `0`
- `uint`: `0`
- `enum`: 枚举中的第一个元素
- `address`: `0x0000000000000000000000000000000000000000` (或 `address(0)`)
- `function`:
- `internal`: 空白函数
- `external`: 空白函数

示例代码:
```solidity
bool public _bool; // false
string public _string; // ""
int public _int; // 0
uint public _uint; // 0
address public _address; // 0x0000000000000000000000000000000000000000
enum ActionSet { Buy, Hold, Sell}
ActionSet public _enum; // 第1个内容Buy的索引0
function fi() internal{} // internal空白函数
function fe() external{} // external空白函数
```

#### 引用类型初始值
- 映射 `mapping`: 所有元素都为其默认值的 `mapping`
- 结构体 `struct`: 所有成员设为其默认值的结构体
- 数组 `array`:
- 动态数组: `[]`
- 静态数组(定长): 所有成员设为其默认值的静态数组

示例代码:
```
solidity
uint[8] public _staticArray; // 所有成员设为其默认值的静态数组[0,0,0,0,0,0,0,0]
uint[] public _dynamicArray; // `[]`
mapping(uint => address) public _mapping; // 所有元素都为其默认值的mapping
// 所有成员设为其默认值的结构体 0, 0
struct Student{
uint256 id;
uint256 score;
}
Student public student;
```

#### `delete` 操作符
`delete a` 会让变量 `a` 的值变为初始值。

示例代码:
```
solidity
bool public _bool2 = true;
function d() external {
delete _bool2; // delete 会让_bool2变为默认值,false
}
```

#### 思考与解答

1. 为什么了解变量的初始值很重要?
- 了解初始值有助于避免潜在的错误和意外行为。例如,在条件判断中,如果不知道 `bool` 类型的初始值是 `false`,可能会导致逻辑错误。

2. 动态数组和静态数组的初始值有什么区别?为什么会有这种区别?
- 动态数组的初始值是空数组 `[]`,而静态数组的初始值是所有元素都设为默认值的数组。这是因为静态数组的长度是固定的,必须在创建时就分配所有空间,而动态数组可以根据需要增长。

3. `delete` 操作符和将变量赋值为其类型的默认值有什么区别?
- 从结果上看,两者是相同的。但 `delete` 操作符更加通用,可以用于任何类型,包括复杂的数据结构。此外,使用 `delete` 可能在某些情况下更节省 gas,因为它直接将存储槽重置为初始状态。


<!-- Content_END -->
29 changes: 29 additions & 0 deletions 0xwangyi.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,32 @@ Solidity 101-12 事件event
12 主题topics包括:哈希keccak256(事件的签名),from,to(除了哈希,topics还可以包括最多3个indexed参数)
13 数据data:事件event中不带indexed的参数会被储存在data中(可以理解成事件event的值value)
<!-- Content_END -->
<!-- Content_START -->
### 2024.09.27
Day5
Solidity 101-13 继承inheritance
1 virtual:父合约中的函数,如果希望子合约重写,需要加上virtual关键字
2 override:子合约重写了父合约中的函数,需要加上override关键字
3 继承时要按辈分最高到最低的顺序排
4 如果某一个函数在多个继承的合约里都存在,在子合约里必须重写,不然会报错
5 重写在多个父合约中都重名的函数时,override关键字后面要加上所有父合约名字,例如override(Yeye, Baba)
6 调用父合约函数-直接调用:子合约可以直接用父合约名.函数名()的方式来调用父合约函数,如Yeye.pop()
7 调用父合约函数-super关键字:子合约可以利用super.函数名()来调用最近的父合约函数
8 is关键字:表示继承(Child is Parent意思是Child合约继承了Parent合约的功能)
<!-- Content_END -->
<!-- Content_START -->
### 2024.09.29
Day7
Solidity 102-17库合约Library Contracts
1 using A for B:使用库合约A的函数来扩展类型B的功能(B类型的变量可以直接调用库合约A的函数)

Solidity 102-18 import
1 import导入
2 npm :Node Package Manager,随Node.js 一起发布的包管理工具
3 Solidity中import的作用是:导入其他合约中的全局符号
4 import导入文件的来源可以是:源文件网址,npm的目录,本地文件
5 import导入文件中的全局符号可以单独指定其中的:合约,纯函数,结构体类型
6 被导入文件中的全局符号想要被其他合约单独导入,应该:与合约并列在文件结构中
7 导入的本地文件会被编译成字节码部署到链上
8 在import 语句中使用*是为了导入一个Solidity 文件中的所有内容,并通过一个命名空间来访问这些内容
<!-- Content_END -->
4 changes: 4 additions & 0 deletions 4-in-truth.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,8 @@ timezone: Asia/Shanghai
今天搬家筋疲力尽,歇一天~~~
###

### 2024.09.27
签到啦~~~~
###

<!-- Content_END -->
Loading

0 comments on commit 65d1460

Please sign in to comment.