合约交互与 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
上一篇 2026年3月8日 15:11
下一篇 2026年3月14日 00:37

相关推荐

  • 动态调用与Fallback机制

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

    2026年3月10日
    5900
  • Solidity 值类型详解

    Solidity 值类型详解 学习目标 掌握 Solidity 的整型、布尔、地址、定长字节数组、枚举等值类型 理解 EVM 256 位机器架构对类型设计的影响 掌握类型转换规则(隐式 vs 显式) 了解溢出问题的历史与解决方案 理解 Solidity 中所有类型的默认值机制 一、整型(int / uint) 1.1 基本概念 Solidity 提供有符号整…

    Web3与WASM 2026年3月10日
    8200
  • 引用类型详解:数组、结构体、映射、字符串

    引用类型详解:数组、结构体、映射、字符串 学习目标 掌握 Solidity 中四种引用类型(数组、结构体、映射、字符串/变长字节数组)的定义和使用方法。 前置知识 已学习值类型(整型、布尔、地址、定长字节数组等)。 数组(Array) storage 中的数组 Solidity 中数组分为两种: 静态数组 T[K]:长度固定,编译时确定 动态数组 T[]:长…

    Web3与WASM 2026年3月10日
    8100
  • 继承多态与库合约

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

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

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

    Web3与WASM 2026年3月10日
    5200
简体中文 繁体中文 English