一、前言

看了一些区块链的教程,论文,在网上刚刚找到了一个项目实战,CryptoZombies。

二、 接口interface

1、讲解

我们写的合约可能会需要和其他地方的合约进行会话,这里我们就需要用到接口。

假如区块链有如下的一个合约:

contract LuckyNumber {
mapping(address => uint) numbers;

function setNum(uint _num) public {
numbers[msg.sender] = _num;
}

function getNum(address _myAddress) public view returns (uint) {
return numbers[_myAddress];
}
}

我们现在有一个外部合约,想要读取上面合约中的数据。我们定义 ​​LuckyNumber​​ 合约的 interface

contract NumberInterface {
function getNum(address _myAddress) public view returns (uint);
}

这个过程虽然看起来像在定义一个合约,但其实内里不同:

1.我们只声明了要与之交互的函数 —— 在本例中为 ​​getNum​​ —— 在其中我们没有使用到任何其他的函数或状态变量。

2.我们并没有使用大括号(​​{​​​ 和 ​​}​​​)定义函数体,我们单单用分号(​​;​​)结束了函数声明。

编译器就是靠这些特征认出它是一个接口的。

在我们的 app 代码中使用这个接口,合约就知道其他合约的函数是怎样的,应该如何调用,以及可期待什么类型的返回值。

2、实战1

1.要求

​getKitty​​的函数返回所有的加密猫的数据,包括它的“基因”(我们的僵尸游戏要用它生成新的僵尸)。

该函数如下所示:

function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
) {
Kitty storage kit = kitties[_id];

// if this variable is 0 then it's not gestating
isGestating = (kit.siringWithId != 0);
isReady = (kit.cooldownEndBlock <= block.number);
cooldownIndex = uint256(kit.cooldownIndex);
nextActionAt = uint256(kit.cooldownEndBlock);
siringWithId = uint256(kit.siringWithId);
birthTime = uint256(kit.birthTime);
matronId = uint256(kit.matronId);
sireId = uint256(kit.sireId);
generation = uint256(kit.generation);
genes = kit.genes;
}

用这个来创建一个接口: 

1.定义一个名为 ​​KittyInterface​​ 的接口。

2.在interface里定义了 ​​getKitty​​ 函数。

2.代码

pragma solidity >=0.5.0 <0.6.0;

import "./zombiefactory.sol";

// Create KittyInterface here
contract KittyInterface {
function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
);
}
contract ZombieFeeding is ZombieFactory {

function feedAndMultiply(uint _zombieId, uint _targetDna) public {
require(msg.sender == zombieToOwner[_zombieId]);
Zombie storage myZombie = zombies[_zombieId];
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
_createZombie("NoName", newDna);
}

}

3、实战2——使用接口

1.介绍

​通过上面的例子,我们将接口定义如下​​:

contract NumberInterface {
function getNum(address _myAddress) public view returns (uint);
}

我们可以在合约中这样使用:

contract MyContract {
address NumberInterfaceAddress = 0xab38...;
// ^ 这是FavoriteNumber合约在以太坊上的地址
NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
// 现在变量 `numberContract` 指向另一个合约对象

function someFunction() public {
// 现在我们可以调用在那个合约中声明的 `getNum`函数:
uint num = numberContract.getNum(msg.sender);
// ...在这儿使用 `num`变量做些什么
}
}

通过这种方式,只要将合约的可见性设置为​​public​​​(公共)或​​external​​(外部),它们就可以与以太坊区块链上的任何其他合约进行交互。

2.作业

我们构建一个自己的合约去读取另一个智能合约 CryptoKitties 的内容。

变量​​ckAddress​​​存放的是CryptoKitties 合约的地址,在下一行中,请创建一个名为 ​​kittyContract​​​ 的 KittyInterface,并用 ​​ckAddress​​ 为它初始化。

3.代码

pragma solidity >=0.5.0 <0.6.0;

import "./zombiefactory.sol";

contract KittyInterface {
function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
);
}

contract ZombieFeeding is ZombieFactory {

address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
// Initialize kittyContract here using `ckAddress` from above
KittyInterface kittyContract = KittyInterface(ckAddress);

function feedAndMultiply(uint _zombieId, uint _targetDna) public {
require(msg.sender == zombieToOwner[_zombieId]);
Zombie storage myZombie = zombies[_zombieId];
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
_createZombie("NoName", newDna);
}

}