---
title: 'Solidity WTF 102 22 ~ 23 單元'
lang: zh-tw
---
Solidity WTF 102 22 ~ 23 單元
===
:::info
:date: 2024/10/04
:::
[TOC]
# 課程學習
## Call
### call 簡介
`call` 是 `address` 類型的低級成員函數,返回值為`(bool, bytes memory)`
- `call`是`發送ETH`的方法,他在發送後會觸發接收方合約的`receive`或是`fallback`
- 不推薦用`call`調用其他合約,以免調用到不安全的合約
- 不確定合約函數或是`ABI`時,還是能透過`call`調用
:::info
:bulb: `call` 是 `address` 類型的低級成員函數,這可能意味著 `call` 函數是直接處理「地址」相關的操作,而「地址」通常是在底層的內存或硬體層級上運作的。這就是為什麼它被稱為低級。
:::
### call 使用規則
```javascript=
目標合约地址.call(字節碼);
```
字節碼是由結構化編碼函數abi.encodeWithSignature獲得
```javascript=
// call 也可以指定ETH數量和gas
目标合约地址.call{value:发送数额, gas:gas数额}(字节码);
abi.encodeWithSignature("函数签名", 逗号分隔的具体参数)
// abi.encodeWithSignature("f(uint256,address)", _x, _addr)
```
### 目標合約
假設今天合約內容如下:
```javascript=
contract OtherContract {
uint256 private _x = 0; // 状态变量x
// 收到eth的事件,记录amount和gas
event Log(uint amount, uint gas);
fallback() external payable{}
// 返回合约ETH余额
function getBalance() view public returns(uint) {
return address(this).balance;
}
// 可以调整状态变量_x的函数,并且可以往合约转ETH (payable)
function setX(uint256 x) external payable{
_x = x;
// 如果转入ETH,则释放Log事件
if(msg.value > 0){
emit Log(msg.value, gasleft());
}
}
// 读取x
function getX() external view returns(uint x){
x = _x;
}
}
```
那我要如何使用`call`調用其中的函數? 使用方法如下:
```javascript=
// 定义Response事件,输出call返回的结果success和data
event Response(bool success, bytes data);
function callSetX(address payable _addr, uint256 x) public payable {
// call setX(),同时可以发送ETH
// 這邊使用與call使用方法相同的abi方式,去調用其他合約內的funciton
(bool success, bytes memory data) = _addr.call{value: msg.value}(
abi.encodeWithSignature("setX(uint256)", x)
);
emit Response(success, data); //释放事件
}
```
### call問題
> 假設`call`一個不存在的函數名稱,會有什麼結果?
:::success
會調用`fallback`函數,若`fallback`函數沒有實現,則會報錯。
:::
> call推薦用來做什麼?
:::success
用來`發送ETH`,因為`transfe`r與`send`都有`gas limit`,若超過會報`out of gas`
:::
## Delegatecall
### delegatecall 簡介
與`call`類似,都是`address`類型的低級函數,有委託/代表的意思。
課程中的圖片很清楚,直接引用,並且在付上較簡單的解釋。


`call`會直接調用`C合約`,結果會直接儲存在`C合約`中。
`delegatecall`委託調用,如果`delegatecall` `C合約`,那我只會借用他`function logic`,值會儲存在`B合約`而不是`C合約`。
### 用法
與`call`大致相同,不同的地方是`delegatecall`在调用合约时可以指定交易发送的`gas`,但不能指定发送的`ETH数额`。
```javascript=
// delegatecall 也可以指定gas 但不能指令eth數量
目标合约地址.delegatecall{value:发送数额, gas:gas数额}(字节码);
abi.encodeWithSignature("函数签名", 逗号分隔的具体参数)
// abi.encodeWithSignature("f(uint256,address)", _x, _addr)
```
#### 何時會用到
- 代理合約
- EIP-2535 Diamonds(鑽石合約)
##### 代理合約
`代理合約`只儲存相關的變數,並保存邏輯合約地址; 函數都會在邏輯合約實作。
如果今天要升級,只需要將`代理合約指向新的邏輯合約`即可。
- B 就是代理合約,C則是邏輯合約。

:::info
:memo: 鑽石合約將獨立出來講解
:::
## 本章重點
應著重在使用方式,以及`delegatecall`觀念。
:::success
:bulb: 兩者差別只能不能指定`eth數量`與儲存參數的位置。
:::