大家知道客户端在调取智能合约时,需要先传递一个 ABI
接口。这样客户端(例如 js
)就可以调取智能合约中的方法了。
那么在 solidity
中如何在当前编写的合约中调取一个已部署的合约呢?也类似,通过声明已部署的合约接口,让当前合约识别老合约。
第一种实现,通过接口调用:
合约调取合约最小实现案例 第一个合约:
1 | pragma solidity ^0.4.24; |
我们部署它,会得到一个合约地址,假设它是 0xxxxx
我们写第二个合约:
1 | pragma solidity ^0.4.24; |
如上面的代码,我们先声明了一个已部署合约的接口:
1 | interface Deployed { |
然后就可以在新的合约 Existing
中调用这个合约了。
我们把第二个合约部署时,把第一个合约 Deployed
的合约地址 0xxxxx
传进来赋值给 _t
,并初始化将第一个合约赋值给 dc
。我们看到 getA
, setA
分别发生了什么?
然后我们分别调取合约1
和合约2
,再去比较。
那么如何用solidity
合约调取erc20
代币的合约呢?
比如snt
啊,loom
啊,knc
啊。
首先我有一个名叫loom
的erc20token
部署在ropsten
网络。
- loom的详细
- 合约地址
0x090652a4aecee28a7ae766c5bd51851830185664
- 合约
- 合约地址
我们写当前的合约向第一个例子一样,先写 erc20token
的接口,接着写我们调用的合约:
1 | pragma solidity ^0.4.24; |
我们将这个合约部署:
同样在 ropsten
测试网中,得到这个合约地址:
然后我们转入一笔 loom
到这个合约地址 0x2C8C3483Be1160A2D89D07708b5477Ea19457255
恩,我们看看转账记录:
接下来,我们调取我们所写的 StandardToken
合约的 transferloomtoken
这个方法,神奇的事又发生了:
这种通过接口调用方式是最为推荐的,当然还有第二种:
另外,这种还有一个技巧,假如你的合约需要调用多个合约,你不需要写多个合约接口,只需要写一个合约接口,然后把所有需要调用的方法都写在这个接口里面。
然后,你用这个接口创建的合约,就可以调用任何一个合约里面的方法了。
第二种方式:使用call,delegatecall
1 | pragma solidity ^0.4.18; |
补充 loom
的教程:与其他合约的交互
定义interface
如果我们的合约需要和区块链上的其他的合约会话,则需先定义一个 interface
(接口)。 先举一个简单的栗子。 假设在区块链上有这么一个合约:
1 | contract LuckyNumber { |
这是个很简单的合约,您可以用它存储自己的幸运号码,并将其与您的以太坊地址关联。 这样其他人就可以通过您的地址查找您的幸运号码了。 现在假设我们有一个外部合约,使用 getNum
函数可读取其中的数据。
首先,我们定义 LuckyNumber
合约的 interface
:
1 | contract NumberInterface { |
请注意,这个过程虽然看起来像在定义一个合约,但其实内里不同:
首先,我们只声明了要与之交互的函数 —— 在本例中为 getNum
—— 在其中我们没有使用到任何其他的函数或状态变量。
其次,我们并没有使用大括号({
和 }
)定义函数体,我们单单用分号(;
)结束了函数声明。这使它看起来像一个合约框架。
编译器就是靠这些特征认出它是一个接口的。
在我们的 app
代码中使用这个接口,合约就知道其他合约的函数是怎样的,应该如何调用,以及可期待什么类型的返回值。
在下一节中,我们将真正调用其他合约的函数。目前我们只要声明一个接口,用于调用 CryptoKitties
合约就行了。
使用接口,调用已用合约方法
继续前面 NumberInterface
的例子,我们既然将接口定义为:
1 | contract NumberInterface { |
我们可以在合约中这样使用:
1 | contract MyContract { |
通过这种方式,只要将您合约的可见性设置为 public
(公共)或 external
(外部),它们就可以与以太坊区块链上的任何其他合约进行交互。