forked from DeFiHackLabs/Solidity-Intensive-CoLearning
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
CHOSEN
committed
Sep 29, 2024
1 parent
7c5c9c6
commit 8d7bd4a
Showing
8 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'; | ||
``` | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); //释放事件 | ||
} | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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是该地址创建合约的次数; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
## Create2 | ||
|
||
// TODO | ||
|
||
## 删除合约 | ||
|
||
### 如何使用 | ||
_addr是当合约被销毁时指定剩余ETH转移的地址,该地址不需要有receive/fallback函数也能接收ETH | ||
``` | ||
selfdestruct(_addr); | ||
``` | ||
### 同笔交易内实现合约创建和销毁 | ||
// TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## ABI编码解码 | ||
|
||
## Hash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |