合约交互与 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://www.walker-learn.xyz/archives/7492

(0)
Walker的头像Walker
上一篇 2026年3月10日 07:00
下一篇 2026年3月10日 05:00

相关推荐

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

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

    Web3与WASM 2026年3月10日
    10300
  • 函数定义与访问控制

    函数定义与访问控制 学习目标 掌握 Solidity 函数定义、可见性修饰符、交易属性、modifier 和构造函数。 函数定义 一般形式 function fname([参数]) [可见性][交易属性][modifier...] returns(返回值) { ... } 函数签名:fname([参数]) —— 唯一标识一个函数 返回值:returns(返回…

    Web3与WASM 2026年3月10日
    6600
  • Gas机制与转账设计

    Gas机制与转账设计 学习目标 理解区块链的经济模型与激励机制 掌握 Gas、Gas Price、Gas Fee 的概念与关系 理解 Ether 单位与转换 掌握合约转账设计(receive / fallback / payable) 区块链的经济系统 为什么需要经济模型? 计算与存储资源是稀缺的:每个节点都要执行和存储所有交易 共识和 trustless …

    2026年3月10日
    6800
  • Solidity 入门与开发环境

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

    2026年3月10日
    10900
  • Delegatecall 与代理模式

    Delegatecall 与代理模式 学习目标 理解 delegatecall 的工作原理 掌握 Storage Layout(存储布局)规则 掌握代理模式与合约升级 了解非结构化存储(Unstructured Storage) delegatecall 原理 什么是 delegatecall 语法:address.delegatecall(bytes ca…

    2026年3月10日
    6400
简体中文 繁体中文 English