当前位置: 首页 > news >正文

call 与 delegatecall - all-in

一、为什么要用底层调用

我们知道,在一个合约中调用另一个合约的接口,通常使用contractName(address).functionName() 来进行调用,比如:

contract MyContract {function add(address _counter) public {// 调用 Counter 合约的方法Counter(_counter).increment();}
}

但是,有时我们在编写合约时,还不知道要调用的目标合约的接口,甚至是目标合约还没有创建。这时就无法用上面的方法进行调用。

这个问题该如何解决呢?

你也许知道很多编程语言(如Java和Go)有反射的概念,反射允许在运行时动态地调用函数或方法。地址的底层调用和反射非常类似。

使用address底层调用功能,是在运行时动态地决定调用目标合约和函数, 因此在编译时,可以不知道具体要调用的函数或方法。

二、底层调用

address类型还有3个底层的成员函数:

<address>.call(bytes memory abiEncodeData) returns (bool, bytes memory)<address>.delegatecall(bytes memory abiEncodeData) returns (bool, bytes memory)<address>.staticcall(bytes memory abiEncodeData) returns (bool, bytes memory)
  • 其中,call 是常规调用,delegatecall 为委托调用,staticcall 是静态调用(不修改合约状态, 相当于调用 view 方法)。

这三个函数都可以用于与目标合约<address>交互,三个函数均接受 abi 编码数据作为参数(abiEncodeData)来调用对应的函数。

这里我们使用底层方法调用一下《手把手教你部署智能合约》中的合约:

contract CallTest {function makeCallGet(address _counter) public view returns (uint) {// staticcall调用bytes memory payload = abi.encodeWithSignature("get()");(bool success, bytes memory returnData) = address(_counter).staticcall(payload);// 判断一下require(success, "Call to target contract failed.");// 将returnData解析成指定类型(e.g. uint)(uint res) = abi.decode(returnData, (uint));return res;}function makeCallCount(address _counter) public {// call调用bytes memory payload = abi.encodeWithSignature("count()");(bool success, ) = address(_counter).call(payload);// 判断一下require(success, "Call to target contract failed.");}
}// https://testnet.routescan.io/address/0xcF10C1b7DA166987a1D9bB81C072C339cb7205fd

使用底层方法调用合约函数时, 当被调用的函数发生异常时(revert),异常不会冒泡到调用者(即不会回退), 而是返回布尔值 false。因此在使用所有这些低级函数时,一定要记得检查返回值

三、call 与 delegatecall

常规调用 call 与 委托调用 delegatecall 的区别是什么呢?

image

  1. 执行上下文:当使用call函数时,被调用的函数在目标合约的上下文中执行,这意味着它有自己的thismsg.sender。而delegatecall函数则在调用合约(当前合约)的上下文中执行被调用的函数。—— 相当于将函数代码 pull 到当前合约中执行

  2. 状态存储call函数在执行时不会改变调用合约的状态,它只会改变被调用合约的状态。而delegatecall函数则可以改变调用合约的状态,因为它在调用合约的上下文中执行。

  3. 用途call函数通常用于调用其他合约的函数,而delegatecall函数允许一个合约借用另一个合约的代码,在自己的上下文中执行,常用于实现可升级合约和库函数。

http://www.rkmt.cn/news/57586.html

相关文章:

  • 洛谷 P5658 [CSP-S 2019] 括号树 题解
  • .NET+AI | MEAI | Function Caling 实操(4)
  • Java中HashMap的核心原理与使用注意事项
  • MinIo介绍 - 努力-
  • 南昌航空大学-ptajava
  • Wi-Fi FTM 技术 10 年后展望
  • Docker使用【镜像】 - 指南
  • 2025年11月22日训练赛
  • Linux命令绕过 - 教程
  • MyBatis Flex 讲解使用
  • 一种自定义二维码的加码、解码、识别和绘制算法的逆向和重构
  • 浅谈最近星某克被指追杀式营销的技术实现方式和商业价值利弊
  • 数据库常用编码和压缩算法介绍
  • hive sql开发有啥优势
  • 完整教程:《工业之心:Blender 工业场景解构》
  • 深入解析:pip 的包下载之后存放在哪?
  • 图书馆管理系统需求改进和系统设计
  • docker compose插件安装
  • 多机elasticsearch集群部署,超详细教程
  • DeepSeek 提取 交易所网站核心500词汇(名词与术语)
  • 2025年布袋除尘器供应商权威推荐榜单:塑烧板除尘器/耐高温除尘器/防爆除尘器源头厂家精选
  • 创建矩形并让矩形移动
  • 2025年稳定土搅拌站供应商权威推荐榜单:搅拌站回收/二手稳定土搅拌站/二手混凝土土搅拌站源头厂家精选
  • 从组件的角度梳理微服务技术栈(1)
  • 树的直径、重心、中心 学习笔记
  • 深入解析:带你了解STM32:WDG看门狗
  • FastAPI docker demo
  • 2025年铁氟龙膜源头厂家权威推荐榜单:特氟龙膜/PTFE膜/聚四氟乙烯膜源头厂家精选
  • 我的代码入选GitHub北极代码库
  • 兰州市一对一培训机构推荐,2026年最新课外辅导补习机构口碑深度测评排名榜