文章目录
  1. 1. AxieCore.sol
  2. 2. AxieAccessControl.sol
  3. 3. 总结

回头一看,居然距离上次写Axie Infinity合约的文章过了整整一年了。这一年因为手头忙,杂事多,也没来得及更新。趁着家人都睡了,再来更新一波吧。

我们先来回顾一下目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
│  AxieAccessControl.sol
│ AxieCore.sol

├─dependency
│ AxieDependency.sol
│ AxieManager.sol
│ AxieManagerCustomizable.sol

├─erc721
│ AxieERC721.sol
│ AxieERC721BaseEnumerable.sol
│ AxieERC721Metadata.sol

└─lifecycle
AxiePausable.sol
AxieUpgradeable.sol

上次把erc721目录基本都讲到了,这也是最核心的部分。上一部分都了解了以后,基本的erc721结构已经清晰了。本来这次是打算先从权限部分来分析,但是出于我心理学专业的本能,我想如果是自己第一次看这个系列,现在更希望看到什么。我猜自己会希望更快的能发布我的NFT,所以这次我们直接先分析最核心文件AxieCore.sol 文件链接:AxieCore.sol

AxieCore.sol

关于头部引入的的 AxieERC721.sol ,我们在上一篇已经讲过了,其作为核心依赖的合约,管理了基础数据(即直译过来的基础可枚举)和扩展属性(即直译过来的元数据)。我们现在更关心的是,Core这个合约它在这个基础上实现了什么功能。

我们来看第一部分:

1
2
3
4
5
6
7
8
// solium-disable-next-line no-empty-blocks
contract AxieCore is AxieERC721 {
struct Axie {
uint256 genes;
uint256 bornAt;
}

Axie[] axies;

有时候真是要感谢代码和命名规范,我们可以很清楚的看到,这个代码在一开始就声明了一个名为 Axie 的结构,它包含了一个256长度Int的基因密钥和一个256长度的出生标记。紧接着就声明了一个axies数组,想必是用来存放生成的axie。我们现在可以猜测,这个合约很可能是在制定一只Axie的生命周期和规则,然后把他们存起来。

下一部分就真正切入主题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  event AxieSpawned(uint256 indexed _axieId, address indexed _owner, uint256 _genes);
event AxieRebirthed(uint256 indexed _axieId, uint256 _genes);
event AxieRetired(uint256 indexed _axieId);
event AxieEvolved(uint256 indexed _axieId, uint256 _oldGenes, uint256 _newGenes);

...

function spawnAxie(
uint256 _genes,
address _owner
)
external
onlySpawner
whenSpawningAllowed(_genes, _owner)
returns (uint256)
{
return _spawnAxie(_genes, _owner);
}

...

function _spawnAxie(uint256 _genes, address _owner) private returns (uint256 _axieId) {
Axie memory _axie = Axie(_genes, now);
_axieId = axies.push(_axie) - 1;
_mint(_owner, _axieId);
AxieSpawned(_axieId, _owner, _genes);
}

...

我省略了不少地方,因为相较而言,我认为这里能够理解,接下来的东西也很好理解。这里更多的是去思考它为什么要做这种设计。这里我们重点放在事件和方法的关联上。可以看到第一个事件就是产卵 event AxieSpawned (可以理解成生成,但是这里理解成产卵更合适),我们往后看,它是通过 _spawnAxie 这个方法触发的。这个方法需要一个基因密钥和一个所有者地址,从而构造生成(铸造)一只axie,并把其id通过 AxieSpawned 事件广播出来。

当然, _spawnAxie 是个private私有方法,而有个专门供external外部调用的 spawnAxie 方法,它可以由拥有产卵权限的用户地址(同时还在被允许的产卵时间里)调用,从而返回所生成axie的信息,并广播事件。

这个逻辑理顺了,其他几个有关出生、死亡、进化等的事件和方法也就迎刃而解了。

还值得一提的是这段代码:

1
2
3
4
5
6
7
8
9
10
11
function getAxie(
uint256 _axieId
)
external
view
mustBeValidToken(_axieId)
returns (uint256 /* _genes */, uint256 /* _bornAt */)
{
Axie storage _axie = axies[_axieId];
return (_axie.genes, _axie.bornAt);
}

这个方法几乎在所有的nft中都会出现,算是基础操作。咱总得有个获取已经生成的nft的方法,对吧?

AxieAccessControl.sol

这个文件其实没什么好讲的,甚至如果比较轻型的团队或比较简单的合约,都会勿略掉权限控制部分。这里大概就是定义了各种各样的修饰器,例如 onlyCEOonlyCOOonlyCLevel 等等,用来控制某些关键操作只能由特定的账户地址来操作。

例如其中比较经典的:

1
2
3
function withdrawBalance() external onlyCFO {
cfoAddress.transfer(this.balance);
}

这里就限制了只有CFO账户地址可以提取资产。

同理其实 dependency/AxieDependency.sol 这个合约也在做类似的事情。如果是类似的事情为什么会分成两个合约还放在归在不同的文件夹中呢?其实仔细分析就会知道,AxieAccessControl 是针对整个Axie Infinity系统而言的,而 AxieDependency 仅仅是针对某一只Axie而言的。

总结

其实讲到这里,Axie Infinity的公开合约中关于核心NFT资产部分也就没什么好分析的了。Core文件夹中的其他合约,都是一些修饰性的内容。而关于如何生成基因密钥,包括怀孕、产卵等比较关建的详细合约,都不在其中。

如果想要了解有关生成一个NFT的过程,可以参考 CryptoKitties 的相关代码,网上有很多公开的分析。当然,有需要,我也可以粗略分析一下。

如果想要了解有关NFT市场的代码,同理搜索 CryptoKitties 的相关信息,附带有讲到相关内容。当然,还是上面那句话,有需要我也可以粗略分析一下。

最后,本人学疏才浅,各位看官如果发现有任何问题或者遗漏,还请帮忙指出来,不胜感激。

♦ 本文固定连接:https://www.gsgundam.com/2022/2022-12-12-axie-contract-how-to-2/

♦ 转载请注明:GSGundam 2022年12月12日发布于 GSGUNDAM砍柴工

♦ 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

♦ 原创不易,如果页面上有适合你的广告,不妨点击一下看看,支持作者。(广告来源:Google Adsense)

♦ 本文总阅读量