合约交互与 ABI

合约交互与 ABI

学习目标

掌握合约间调用方式、接口定义、ABI 数据结构、Web3.js 访问合约的方法。


合约间调用基础

  • EOA(外部账号)发起调用,可能触发合约间的调用链
  • 调用者必须持有被调用合约的地址

方式一:同文件内直接调用

当两个合约在同一个文件中时,可以直接通过合约类型和地址进行调用:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

contract Callee {
    uint256 public x;

    function setX(uint _x) public {
        x = _x;
    }
}

contract Caller {
    address calleeAddress;

    constructor(address _callee) {
        calleeAddress = _callee;
    }

    function setCalleeX(uint _x) public {
        Callee callee = Callee(calleeAddress);
        callee.setX(_x);
    }
}

方式二:跨文件 import 调用

当合约分布在不同文件中时,使用 import 引入:

// 文件: Callee.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

contract Callee {
    uint256 public x;

    function setX(uint _x) public {
        x = _x;
    }
}
// 文件: Caller.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;
import "contracts/Callee.sol";

contract Caller {
    address calleeAddress;

    constructor(address _callee) {
        calleeAddress = _callee;
    }

    function setCalleeX(uint _x) public {
        Callee callee = Callee(calleeAddress);
        callee.setX(_x);
    }
}

方式三:通过接口调用

接口(Interface)等价于 ABI,不依赖被调用合约的源码,只需知道函数签名即可调用。

定义接口

// 文件: ICallee.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

interface ICallee {
    function setX(uint _x) external;
}

实现接口(不强制)

// 文件: Callee.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;
import "contracts/ICallee.sol";

contract Callee is ICallee {
    uint256 public x;

    function setX(uint _x) public {
        x = _x;
    }
}

通过接口调用

// 文件: Caller.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;
import "contracts/ICallee.sol";

contract Caller {
    address calleeAddress;

    constructor(address _callee) {
        calleeAddress = _callee;
    }

    function setCalleeX(uint _x) public {
        ICallee callee = ICallee(calleeAddress);
        callee.setX(_x);
    }
}

实际案例:访问 USDT 合约

只需知道合约地址和接口,就能与链上已部署的合约交互。

  • USDT 合约地址:0xdAC17F958D2ee523a2206206994597C13D831ec7
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

interface IERC20 {
    function name() external view returns(string memory);
    function symbol() external view returns(string memory);
    function decimals() external view returns(uint8);
}

通过接口 + 地址即可读取 USDT 的名称、符号和精度,无需获取 USDT 的源码。


ABI(Application Binary Interface)

ABI 是合约的二进制接口描述,包含以下特征:

  • 只有函数签名信息,没有实现代码
  • EOA 通过 ABI 调用合约,合约之间通过接口调用
  • 编译合约时自动生成

ABI 示意图

ABI JSON 示例

{
    "abi": [
        {
            "inputs": [
                {
                    "internalType": "uint256",
                    "name": "_x",
                    "type": "uint256"
                }
            ],
            "name": "setX",
            "outputs": [
                {
                    "internalType": "uint256",
                    "name": "",
                    "type": "uint256"
                }
            ],
            "stateMutability": "nonpayable",
            "type": "function"
        }
    ]
}

Web3.js 合约访问

Web3.js 是浏览器端调用合约的 JavaScript 库,支持两种引入方式:

  • 直接引用 <script> 标签
  • Node.js 模块(npm install web3

使用步骤

  1. 导入 Web3.js
  2. 调起 MetaMask 登录,获取用户账户地址
  3. 用 ABI + 合约地址生成 contract 对象
  4. 调用合约方法
  5. 读操作(view/pure):.methods.funcName().call()
  6. 写操作(修改状态):.methods.funcName().send({ from: account })

代码示例

// 1. 导入 Web3(浏览器环境,MetaMask 注入 window.ethereum)
const web3 = new Web3(window.ethereum);

// 2. 请求 MetaMask 授权登录
const accounts = await window.ethereum.request({
    method: "eth_requestAccounts"
});
const account = accounts[0];

// 3. 用 ABI + 合约地址创建 contract 对象
const abi = [ /* 合约 ABI JSON */ ];
const contractAddress = "0x1234...abcd";
const contract = new web3.eth.Contract(abi, contractAddress);

// 4a. 读操作(view 函数,不消耗 gas)
const value = await contract.methods.getX().call();
console.log("当前值:", value);

// 4b. 写操作(修改状态,消耗 gas,需要签名)
await contract.methods.setX(42).send({ from: account });

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/7492

(0)
Walker的头像Walker
上一篇 5天前
下一篇 2025年3月27日 15:01

相关推荐

  • 存储位置与拷贝机制:storage、memory、calldata

    存储位置与拷贝机制:storage、memory、calldata 学习目标 理解 EVM 中三种数据存储位置的特点,以及引用类型在不同存储位置之间赋值时的拷贝规则。 前置知识 已学习值类型和引用类型(数组、结构体、映射、字符串)。 三种存储位置 storage —— 持久化存储 类似数据库,数据永久保存在区块链上 成员变量(状态变量)默认存储在 stora…

  • 继承多态与库合约

    继承多态与库合约 学习目标 掌握 Solidity 继承机制与多态 理解 C3 线性化算法 掌握库合约(library)的定义和使用 继承基础 继承定义 使用 is 关键字 继承的实现方式是代码拷贝:部署后变成一个合约 可见性与继承 private:子合约不可见,但不能定义同名成员 internal:子合约可见 public:完全可见 event 和 mod…

    Web3与WASM 20小时前
    200
  • 动态调用与Fallback机制

    动态调用与Fallback机制 学习目标 掌握 call 动态调用的语法与使用场景 理解 calldata 数据结构(selector + 参数编码) 掌握 fallback / receive 函数的触发机制 理解 tx、msg、block 三种上下文变量的区别 call 动态调用 基本语法 (bool success, bytes memory data…

    23小时前
    200
  • Solidity 入门与开发环境

    Solidity 入门与开发环境 学习目标 理解智能合约的本质与核心特性 掌握合约在以太坊上的运行原理(Transaction + EVM) 认识 Solidity 语言特点与开发工具链 编写并部署第一个智能合约 前置知识 了解区块链基本概念(区块、交易、共识) 了解以太坊账户模型(EOA 与合约账户) 基本编程经验(任意语言均可) 一、智能合约的根本性质 …

    1天前
    1200
  • Web3 概述与愿景

    Web3 概述与愿景 学习目标 理解 Web1、Web2、Web3 的演进历程与核心区别 掌握 Web3 的核心理念:去中心化、数据确权、用户主权 了解 Web3 带来的创新机会与全新商业模式 熟悉 Web3 开发者的学习路线图 前置知识 基本的互联网使用经验 对软件开发有初步了解(非必须,但有助于理解技术部分) 一、Web1 → Web2 → Web3 的…

    Web3与WASM 19小时前
    600
简体中文 繁体中文 English