【从0学习Solidity】22. Call函数详解

news2024/11/24 19:39:08

【从0学习Solidity】22. Call函数详解

在这里插入图片描述

  • 博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。
  • 关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!
  • 本文收录于 不写代码没饭吃 的学习汇报系列,大家有兴趣的可以看一看。
  • 欢迎访问我们的微信公众号:不写代码没饭吃,获取更多精彩内容、实用技巧、行业资讯等。您关注的是我们前进的动力!

我们曾在第20讲:发送ETH那一讲介绍过利用call来发送ETH,这一讲我们将介绍如何利用它调用合约。

Call

calladdress类型的低级成员函数,它用来与其他合约交互。它的返回值为(bool, data),分别对应call是否成功以及目标函数的返回值。

  • callsolidity官方推荐的通过触发fallbackreceive函数发送ETH的方法。
  • 不推荐用call来调用另一个合约,因为当你调用不安全合约的函数时,你就把主动权交给了它。推荐的方法仍是声明合约变量后调用函数,见第21讲:调用其他合约
  • 当我们不知道对方合约的源代码或ABI,就没法生成合约变量;这时,我们仍可以通过call调用对方合约的函数。

call的使用规则

call的使用规则如下:

目标合约地址.call(字节码);

其中字节码利用结构化编码函数abi.encodeWithSignature获得:

abi.encodeWithSignature("函数签名", 逗号分隔的具体参数)

函数签名"函数名(逗号分隔的参数类型)"。例如abi.encodeWithSignature("f(uint256,address)", _x, _addr)

另外call在调用合约时可以指定交易发送的ETH数额和gas

目标合约地址.call{value:发送数额, gas:gas数额}(字节码);

看起来有点复杂,下面我们举个call应用的例子。

目标合约

我们先写一个简单的目标合约OtherContract并部署,代码与第19讲中基本相同,只是多了fallback函数。

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;
    }
}

这个合约包含一个状态变量x,一个在收到ETH时触发的事件Log,三个函数:

  • getBalance(): 返回合约ETH余额。
  • setX(): external payable函数,可以设置x的值,并向合约发送ETH
  • getX(): 读取x的值。

利用call调用目标合约

1. Response事件

我们写一个Call合约来调用目标合约函数。首先定义一个Response事件,输出call返回的successdata,方便我们观察返回值。

// 定义Response事件,输出call返回的结果success和data
event Response(bool success, bytes data);

2. 调用setX函数

我们定义callSetX函数来调用目标合约的setX(),转入msg.value数额的ETH,并释放Response事件输出successdata

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); //释放事件
}

接下来我们调用callSetX把状态变量_x改为5,参数为OtherContract地址和5,由于目标函数setX()没有返回值,因此Response事件输出的data0x,也就是空。

22-1.png

3. 调用getX函数

下面我们调用getX()函数,它将返回目标合约_x的值,类型为uint256。我们可以利用abi.decode来解码call的返回值data,并读出数值。

function callGetX(address _addr) external returns(uint256){
	// call getX()
	(bool success, bytes memory data) = _addr.call(
		abi.encodeWithSignature("getX()")
	);

	emit Response(success, data); //释放事件
	return abi.decode(data, (uint256));
}

Response事件的输出,我们可以看到data0x0000000000000000000000000000000000000000000000000000000000000005。而经过abi.decode,最终返回值为5

22-2.png

4. 调用不存在的函数

如果我们给call输入的函数不存在于目标合约,那么目标合约的fallback函数会被触发。

function callNonExist(address _addr) external{
	// call 不存在的函数
	(bool success, bytes memory data) = _addr.call(
		abi.encodeWithSignature("foo(uint256)")
	);

	emit Response(success, data); //释放事件
}

上面例子中,我们call了不存在的foo函数。call仍能执行成功,并返回success,但其实调用的目标合约fallback函数。

22-3.png

总结

这一讲,我们介绍了如何用call这一低级函数来调用其他合约。call不是调用合约的推荐方法,因为不安全。但他能让我们在不知道源代码和ABI的情况下调用目标合约,很有用。

在这里插入图片描述

如果这份博客对大家有帮助,希望各位给作者一个免费的点赞👍作为鼓励,并评论收藏一下⭐,谢谢大家!!!
制作不易,如果大家有什么疑问或给作者的意见,欢迎评论区留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1034517.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kux转mp4,实测有效,有图有真相

kux转mp4 kux视频格式真坑爹,我在MAC下载优酷,居然无法播放这种格式,这就是优酷专属的下载格式啊,真不是一般烦人。故而切换到window系统,实验了一下午,找了所有单独的第三方软件,下载的时候一个…

倒置字符串(牛客)

一、题目 二、代码 #include <iostream> #include<string> using namespace std;int main() {string s;getline(cin, s);string s2;int i s.length() - 1;int prev i;int next 0;while (i > 0 && prev > 0) { //从字符串的最后往前遍历if (s[pre…

排序子序列(牛客)

目录 一、题目 二、代码 &#xff08;一&#xff09;时间复杂度过高&#xff08;通过70%&#xff09; &#xff08;二&#xff09;改进 一、题目 二、代码 &#xff08;一&#xff09;时间复杂度过高&#xff08;通过70%&#xff09; #include <iostream> #includ…

C语言内功修炼--指针详讲(进阶)

前言&#xff1a; 通过之前的指针初阶讲解&#xff0c;相信大家已经大概明白了指针的概念以及基本用法&#xff0c;这里我再来整理一下&#xff1a; 1.指针就是一个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识着内存的一块空间。 2.指针具有类型&#xff0c;指针…

单元测试的重要性

前言 在日常生活中&#xff0c;单元测试无论是对软件测试人员还是开发人员&#xff0c;都扮演着重要的角色。这主要是因为&#xff0c;单元测试在开发阶段&#xff0c;可以确保每个组件和程序都能够正常的运行。 很多开发人员都讨厌编写单元测试&#xff0c;但是它可以在开发…

变量使用、

六&#xff1a;变量使用 1.语法格式 变量调用语法&#xff1a; {{ var_name }} 案例&#xff1a; 通过命令行传递变量&#xff1a;&#xff08;通过--extra-vars或-e选项来传递keyvalue变量&#xff09; vim var.yaml 传递字典(同时传递多个变量) vim var-1.yaml 案例二…

竞赛 基于深度学习的行人重识别(person reid)

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的行人重识别 该项目较为新颖&#xff0c;适合…

居家养老一键通的功能

居家养老一键通的功能 居家养老一键通是指为老年人提供全方位的居家养老服务的平台或系统。它通过整合各种资源和服务&#xff0c;为老年人提供便捷、安全、舒适的居家养老环境&#xff0c;帮助他们解决生活中的各种难题。 居家养老一键通的功能通常包括以下几个方面&#xff…

深拷贝与浅拷贝(对象的引用)

可以用赋值 1.对象的引用 代码&#xff1a; <!-- 1.对象的引用 --><script>const info{name:"lucy",age:20}const objinfo;info.name"sam"console.log(obj.name) //sam</script>图解&#xff1a; 等于号的赋值&#xff0c;对象info…

ARMv7-A 那些事 - 4.处理器模式与特权等级

By: Ailson Jack Date: 2023.09.23 个人博客&#xff1a;http://www.only2fire.com/ 本文在我博客的地址是&#xff1a;http://www.only2fire.com/archives/156.html&#xff0c;排版更好&#xff0c;便于学习&#xff0c;也可以去我博客逛逛&#xff0c;兴许有你想要的内容呢。…

二、iMove-cli 本地开发模式

引言&#xff1a;iMove cli肩负着落库逻辑代码的重要责任&#xff0c;本文主要介绍本地开发模式下cli的工作。 书接上文&#xff0c;iMove主要由3个包组成&#xff1a;cli、compile-code、core&#xff0c;此外还有一个插件库plugin-store&#xff0c;这个后续文章再出&#xf…

机器学习的数据

数据 数据整体的信息 我们整个数据就可以表示成这样 上图中的数据整体叫数据集(data set)图中每一行数据称为一个样本(sample)。除最后一列&#xff0c;每一列表达样本的一个特征(feature)最后一列称为标记&#xff08;label&#xff09; 除了第一行和最后一列以外的信息就是…

el table 修改鼠标在行上改变背景颜色

el table 在制作的时候&#xff0c;需要修改当鼠标停留在指定行上的时候&#xff0c;修改背景颜色等相关样式。 这里面记录一下 1. 首先&#xff0c;在table上面添加class&#xff0c;如下图: 2. 然后再最下面下面创建style样式&#xff0c;是<style scoped> 的&#x…

滑动窗口9.23

1876.长度为3且各字符不同的子字符串 1876. 长度为三且各字符不同的子字符串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/substrings-of-size-three-with-distinct-characters/?envTypelist&envId24zW97w8自写思路&#xff1a; 数组充当哈希表…

Spring面试题16:Spring框架中的单例bean是线程安全的吗?Spring框架中bean的生命周期?哪些是重要的bean生命周期方法?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring框架中的单例bean是线程安全的吗?为什么? 是的,Spring框架中的单例Bean是线程安全的。 Spring中的单例Bean默认是在容器启动时创建的,并…

【Cpp】位图Bitmap

code #include <iostream> #include <vector> #include <stdio.h> #include <stdint.h>class Bitmap { private:std::vector<uint8_t> data; // 存储位图数据的字节数组uint32_t size; // 位图的大小&#xff08;以位为单位&#x…

springboot整合aop,实现日志操作

前言&#xff1a; 整合之前&#xff0c;我们要明白aop是什么&#xff0c;为什么要用aop&#xff0c;aop能帮我们做什么。 答&#xff1a;AOP是面向切面编程&#xff08;Aspect-Oriented Programming&#xff09;的简称&#xff0c;它是一种编程思想&#xff0c;旨在在面向对象…

【AI视野·今日Sound 声学论文速览 第十期】Fri, 22 Sep 2023

AI视野今日CS.Sound 声学论文速览 Fri, 22 Sep 2023 Totally 1 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers Performance Conditioning for Diffusion-Based Multi-Instrument Music Synthesis Authors Ben Maman, Johannes Zeitler, Meinard M lle…

数据库中的DDL与DML

标签&#xff1a;数据库 记录下DDL和DML的相关概念。 数据定义语言 定义数据库模式 数据定义语言DDL(Data-Definition Language)可定义数据库模式。数据库模式在之前的文章中已经提到过了。简单来说&#xff0c;建表用的SQL语句就是DDL。如下代码 CREATE TABLE department(de…

使用Python做一个微信机器人

介绍 简介 该程序将微信的内部功能提取出来&#xff0c;然后在程序里加载Python&#xff0c;接着将这些功能导出成库函数&#xff0c;就可以在Python里使用这些函数 程序启动的时候会执行py_code目录下的main.py&#xff0c;类似于你在命令行使用python main.py。 现在会以…