跳转到主要内容

从 Solidity 与其他合约交互

智能合约
Solidity
Remix
部署
可组合性
高级
jdourlens
2020年4月5日
5 分钟阅读

在之前的教程中,我们学习了很多关于如何部署你的第一个智能合约的知识,并为其添加了一些功能,例如使用修饰符控制访问 (opens in a new tab)Solidity 中的错误处理 (opens in a new tab)。在本教程中,我们将学习如何从现有合约部署智能合约并与之交互。

我们将编写一个合约,通过为其创建一个工厂,使任何人都能拥有自己的 Counter 智能合约,其名称将是 CounterFactory。首先,这是我们最初的 Counter 智能合约的代码:

请注意,我们稍微修改了合约代码,以跟踪工厂的地址和合约所有者的地址。当你从另一个合约调用合约代码时,msg.sender 将指向我们合约工厂的地址。这是一个非常需要理解的重点,因为使用一个合约与其他合约交互是一种常见做法。因此,在复杂情况下,你应该注意发送者是谁。

为此,我们还添加了一个 onlyFactory 修饰符,以确保改变状态的函数只能由工厂调用,工厂会将原始调用者作为参数传递。

在我们将用来管理所有其他 Counter 的新 CounterFactory 中,我们将添加一个映射,将所有者与其 counter 合约的地址关联起来:

mapping(address => Counter) _counters;

在以太坊中,映射(mapping)相当于 JavaScript 中的对象,它们能够将类型 A 的密钥映射到类型 B 的值。在这种情况下,我们将所有者的地址与其 Counter 的实例映射起来。

为某人实例化一个新的 Counter 将如下所示:

  function createCounter() public {
      require (_counters[msg.sender] == Counter(0));
      _counters[msg.sender] = new Counter(msg.sender);
  }

我们首先检查该人是否已经拥有一个 counter。如果他没有 counter,我们通过将他的地址传递给 Counter 构造函数来实例化一个新的 counter,并将新创建的实例分配给映射。

要获取特定 Counter 的计数,它将如下所示:

function getCount(address account) public view returns (uint256) {
    require (_counters[account] != Counter(0));
    return (_counters[account].getCount());
}

function getMyCount() public view returns (uint256) {
    return (getCount(msg.sender));
}

第一个函数检查给定地址的 Counter 合约是否存在,然后从实例中调用 getCount 方法。第二个函数:getMyCount 只是一个简写,用于将 msg.sender 直接传递给 getCount 函数。

increment 函数非常相似,但将原始交易发送者传递给 Counter 合约:

function increment() public {
      require (_counters[msg.sender] != Counter(0));
      Counter(_counters[msg.sender]).increment(msg.sender);
  }

请注意,如果调用次数过多,我们的 counter 可能会成为溢出的受害者。你应该尽可能多地使用 SafeMath 库 (opens in a new tab) 来防止这种可能的情况。

要部署我们的合约,你需要同时提供 CounterFactoryCounter 的代码。例如,在 Remix 中部署时,你需要选择 CounterFactory。

这是完整代码:

编译后,在 Remix 部署部分,你将选择要部署的工厂:

Selecting the factory to be deployed in Remix

然后你可以试用你的合约工厂并检查值的变化。如果你想从不同的地址调用智能合约,你需要在 Remix 的账户(Account)选择中更改地址。