A合约调用B合约的四种方法 / 学习智能合约#69

@lemooljiang · 2025-09-24 07:02 · HIVE CN 中文社区

在Solidity中,合约间的调用非常普遍且重要。这里就做个总结。以前的文章有些零散,归纳下,且做些参考。

A合约调用B合约有四种方法,如下: 1.合约对象,2.继承,3.接口, 4.低级调用,call和delegatecall

这些调用方法可以增强合约的灵活性,使其能够执行跨合约操作,比如获取数据、转移资金或触发其他合约的功能。具体的应用场景需具体实现。

1.合约对象

直接生成合约对象来调用。这和很多语言的对象化编程是相通的。

contract FuncAdd {
   uint x = 263;
   function add(uint x, uint y) external returns(uint) { 
      return x;
   };
}

contract TestAdd {
    //用合约地址来实例化接口
    FuncAdd t = FuncAdd(0x3dA5048CE9384a35fF4F3AAF0B4804114e584039);
    function test(uint x, uint y) public returns(uint){
        return t.add(x, y);
    }
}

2.继承

继承A合约中的方法,可以直接调用。

contract A {
    uint public x;
    function setValue(uint _x) public {
        x = _x;
    }
}

contract B is A {
    function modify(uint _y) public {
        setValue(_y); //可以直接调用A合约中的方法
    }
}

3.接口

接口有点类似抽象合约的功能,可用于两个合约间的调用。是非侵入式接口,也就是不用显式的调用接口。在ERC20合约中比较常见。 注意:B中引用A的接口,A的函数仍会在A的环境中执行。

接口合约

一个合约想调用另一个合约的方法时,尽量用接口来调用,不要用call, delegatecall。

interface IFuncAdd {
    function add(uint x, uint y) external returns(uint);
}
contract TestAdd {
    //用合约地址来实例化接口
    IFuncAdd t = IFuncAdd(0x3dA5048CE9384a35fF4F3AAF0B4804114e584039);
    function test(uint x, uint y) public returns(uint){
        return t.add(x, y);
    }
}

4. call和delegatecall

call 会切换到被调合约中去执行方法,会切换上下文。msg.sender是主调合约地址。

delegatecall 则是将被调合约中的方法调到本合约中执行,也就是不会切换上下文。msg.sender是发起者本人。

另外,还有staticcall是 call 的只读版本,适用于调用不会修改状态的函数。在调用期间,合约的状态无法被改变。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract SetNum {
    uint256 public n = 20;
    address public sender;

    function setN(uint256 _n) public {
        n = _n;
        sender = msg.sender;
    }
}

contract CallSet {
    uint256 public n = 15;
    address public sender;

    function CallTest(address _addr, uint256 _n) public {
        _addr.call(abi.encodeWithSignature("setN(uint256)", _n));  //改变SetNum中的n值
        sender = msg.sender;  //是调用者本人,同时会改变SetNum的sender地址

        //(bool success, bytes memory returnData) = _addr.staticcall(data);
    }

    function delegatecallTest(address _addr, uint256 _n) public {
        _addr.delegatecall(abi.encodeWithSignature("setN(uint256)", _n)); //改变自身的n值
        //(bool success, bytes memory data) = _contract.delegatecall(
        //     abi.encodeWithSignature("setVars(uint256)", _num)
        // );
        sender = msg.sender;  //是调用者本人,不会改变SetNum的sender地址
    }
}

// 注意: delegatecall是相当于将被调合约的函数引入自身中执行,所以,这两个合约中的状态变量要一致!否则容易出错。
// 传入的参数(address _addr)是合约地址。

Solidity提供了这四种主要的合约间的调用方法,包括合约对象调用、合约继承,低级调用和接口调用。每种方法都有其适用的场景和特点。开发时要根据具体需求选择合适的调用方式。在合约调用过程中,安全性问题要特别重视,尤其是低级调用中会有重入攻击等危险性,要做好合约的安全工作。

#cn #cn-reader #miao #smartcontract #blockchain #ethereum #solidity
Payout: 0.000 HBD
Votes: 49
More interactions (upvote, reblog, reply) coming soon.