Skip to content

Commit

Permalink
0929
Browse files Browse the repository at this point in the history
  • Loading branch information
CHOSEN committed Sep 29, 2024
1 parent 7c5c9c6 commit 8d7bd4a
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Eric.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ day06:

[WTF Academy Solidity 101 11-12 Note](/content/Eric/106.md)

### 2024.09.29

day07:

[WTF Academy Solidity 101 13-14 Note](/content/Eric/107.md)





Expand Down
57 changes: 57 additions & 0 deletions content/Eric/109.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## 库合约
### 库合约和普通合约的区别
* 不能存在状态变量
* 不能够继承和被继承
* 不能接受以太币
* 不可以被销毁
* 库合约的可见效为public或者external时,为delegatecall调用

### 如何使用库合约
1. 使用using for 指令
```
// 利用using for指令
using Strings for uint256;
function getString1(uint256 _number) public pure returns(string memory){
// 库合约中的函数会自动添加为uint256型变量的成员
return _number.toHexString();
}
```
2. 通过库合约名称调用函数
```
// 直接通过库合约名调用
function getString2(uint256 _number) public pure returns(string memory){
return Strings.toHexString(_number);
}
```
### 常用的库合约有
* Strings:将uint256转换为String
* Address:判断某个地址是否为合约地址
* Create2:更安全的使用Create2 EVM opcode
* Arrays:跟数组相关的库合约
## Import
### 通过源文件相对位置导入
```
文件结构
├── Import.sol
└── Yeye.sol

// 通过文件相对位置import
import './Yeye.sol';
```
### 通过网址引入
```
// 通过网址引用
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol';
```
### 通过npm目录导入
```
import '@openzeppelin/contracts/access/Ownable.sol';
```
### 指定全局符号
```
import {Yeye} from './Yeye.sol';
```
78 changes: 78 additions & 0 deletions content/Eric/110.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
## 接收ETH
### 接受ETH函数-receive
1. receive写法
```
event Received(address _add, uint256 value);
receive() external payable{
emit Received(msg.sender, msg.value);
}
```
2. 注意点
* receive 函数不能写的太复杂,如果别人用send或transfer发送eth的话,因为这两个函数会限制gas费,就会造成“out of gas”发送eth失败

### 回退函数-fallback

1. 写法
```
event fallbackCalled(address _add, uint256 value);
fallback() external payable{
emit fallbackCalled(msg.sender, msg.value);
}
```

### receive和fallback的区别
receive和fallback函数可存在同一个合约,当合约接收ETH时,只会有其中一个函数被触发;
* 当msg.data为空且存在receive函数时会触发receive;
* 当msg.data不为空或者不存在receive函数时触发fallback;
* 如果这两个函数都不存在,则其他合约向该合约发送ETH时会报错;


## 发送ETH
三种方式发送ETH,send,transfer,call
### transfer
代码样例
```
// 用transfer发送eth
function transferETH(address payable _to, uint256 amount) external payable{
_to.transfer(amount);
}
```
* 用法:接收方.transfer(发送eth的金额) // 这个跟java用法不一样
* 转帐限制gas费2300,所有接收的函数不能写的太复杂,通常就是打印一下日志
* transfer如果失败,会自动revert // revert相当于java里面的throw 抛出异常

### send
用法跟transfer一样,唯一的区别的地方在于失败不会自动revert,需要通过接收bool,手动revert
例如:
```
error SendFailed(); // 用send发送ETH失败error
// send()发送ETH
function sendETH(address payable _to, uint256 amount) external payable{
// 处理下send的返回值,如果失败,revert交易并发送error
bool success = _to.send(amount);
if(!success){
revert SendFailed();
}
}
```

### call
上代码
```
error CallETHFail(address _to, uint256 amount); //自定义异常
function callETH(address payable _to, uint256 amount) external payable{
(bool success,) = _to.call{value:amount}("");
if(!success){
revert CallETHFail(_to,amount);
}
}
```
* call函数没有gas费限制,是官方推荐的方式
* 需要通过解构式的方式接受转账结果,手动revert


54 changes: 54 additions & 0 deletions content/Eric/111.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
## 调用其他合约
前提:已知其他合约代码(或接口)且已知其他合约地址
### 传入合约地址
上代码
```
function callSetX(address _add, uint256 x) external {
OtherContract(_add).set(x);
}
```

### 传入合约变量
上代码
```
function callGetX(OtherContract _Address) external view returns(uint x){
x = _Address.getX();
}
```

### 调用合约并发送ETH
上代码
```
function setXTransferETH(address otherContract, uint256 x) payable external{
OtherContract(otherContract).setX{value: msg.value}(x);
}
```

## Call
使用方式
```
目标合约地址.call{value:发送eth金额}(字节码);
// 其中字节码利用结构化编码函数abi.encodeWithSignature获得:
abi.encodeWithSignature("函数签名", 逗号分隔的具体参数)
```

* call函数是官方推荐发送ETH的方法
* call函数并不推荐用来调用其他合约的函数,但有个例外,是当你只知道对方合约地址,但是不知道合约的代码或者ABI(JSON格式的描述文件)时,可以用call来调用

### 利用call来调用其他函数
```
// 定义Response事件,输出call返回的结果success和data
event Response(bool success, bytes data);
function callSetX(address payable _addr, uint256 x) public payable {
// call setX(),同时可以发送ETH
(bool success, bytes memory data) = _addr.call{value: msg.value}(
abi.encodeWithSignature("setX(uint256)", x)
);
emit Response(success, data); //释放事件
}
```

53 changes: 53 additions & 0 deletions content/Eric/112.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## DelegateCall
### DelegateCall和Call的区别
A合约委托调用B合约,执行的是B合约的函数,但是状态变量和上下文都是A的

### 什么情况下会用到DelegateCall
DelegateCall将代理合约和逻辑合约分开,状态变量和上下文都存储在代理合约中,逻辑合约只负责提供所有的函数,
这样当需要升级的时候,只需要将逻辑合约的地址替换掉就可以无缝升级了

### 例子
```
// 被调用的合约C(逻辑合约)
contract C {
uint public num;
address public sender;
function setVars(uint _num) public payable {
num = _num;
sender = msg.sender;
}
}
// 代理合约
contract B {
uint public num;
address public sender;
// 通过call来调用C的setVars()函数,将改变合约C里的状态变量
function callSetVars(address _addr, uint _num) external payable{
// call setVars()
(bool success, bytes memory data) = _addr.call(
abi.encodeWithSignature("setVars(uint256)", _num)
);
}
}
```

## 在合约中创建新合约
用户可以创建合约,合约同样也可以创建合约,
去中心化交易所uniswap就是通过工程合约(PairFactory)创建了无数个币对合约(Pair)
有两种方式可以创建合约,先讲Create
### Create
Create的用法很简单,就是new一个合约;
x是合约对象(地址),如果构造函数是payable,可以在创建时转入_value数量的ETH;
params是构造函数的参数
```
Contract x = new Contract{value:_value}(params);
```
#### create如何计算出地址
```
新地址 = hash(调用者地址,nonce);
```
对于用户来说,调用者地址是钱包地址,nonce是该钱包交易的次数;
对于合约来说,调用者地址是合约地址,nonce是该地址创建合约的次数;
13 changes: 13 additions & 0 deletions content/Eric/113.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Create2

// TODO

## 删除合约

### 如何使用
_addr是当合约被销毁时指定剩余ETH转移的地址,该地址不需要有receive/fallback函数也能接收ETH
```
selfdestruct(_addr);
```
### 同笔交易内实现合约创建和销毁
// TODO
3 changes: 3 additions & 0 deletions content/Eric/114.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## ABI编码解码

## Hash
16 changes: 16 additions & 0 deletions content/Eric/115.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
## 选择器
当我们调用合约时,本质上是向该合约发送了一段**calldata**,可以在input(输入)中看到此次交易的**calldata**
发送calldata的前4个字节是selector(函数选择器),后面32个字节是输入的参数,其实calldata就是告诉合约,我要
调用哪个函数,以及参数是什么

### msg.data
msg.data = method id + 32个字节的参数

### method id,selector
method id 是函数签名哈希值的前4个字节

### 函数签名

函数签名 = 函数名(逗号分割的参数类型)

## Try Catch

0 comments on commit 8d7bd4a

Please sign in to comment.