Moonbirds Smart Contract Nesting 功能浅析
Moonbirds可以说是近几天来最炙手可热的NFT项目,2.5E的高昂公售价格,短短2天时间已经涨到19E的地板价,并实现了超过70,000E的二级市场交易量,项目上线以来一直盘踞Opensea日交易量榜单第一。
除了有私密俱乐部会员资格(private club membership)、PROOF私有Discord会员资格以及 PROOF未来元宇宙项目access等utility外,Moonbirds还有一个全新开发的功能:Nesting。
根据项目官网说明,在开启Nesting之后,拥有者可以在其Moonbirds不离开钱包的情况下进行锁定(lock up),并通过累积Nesting时间让Moonbirds得到升级,以获得未来项目方更多的空投与奖励。
让我们阅读Moonbirds智能合约的源代码,看看其Nesting功能是如何实现的。
mapping(uint256 => uint256) private nestingStarted;
首先为每一个tokenId映射一个nestingStarted的开始时间值,0即此Moonbirds没有在nesting;
mapping(uint256 => uint256) private nestingTotal;
然后再为每一个tokenId映射一个nestingTotal的时间数值,即某个tokenId的Moonbirds的nesting总时间累积值;这里可以注意到,nestingTotal总累积值是根据某一个具体tokenId进行积累,与token owner无关,因此Moonbirds交易与转移并不会重置nestingTotal的数值;
function nestingPeriod(uint256 tokenId)
external
view
returns (
bool nesting,
uint256 current,
uint256 total
)
{
uint256 start = nestingStarted[tokenId];
if (start != 0) {
nesting = true;
current = block.timestamp - start;
}
total = current + nestingTotal[tokenId];
}
这里定义了一个外部调用的可视函数nestingPeriod,对每一个输入的tokenId返回三个值:
是否正在nesting(nestingStarted不等于0就表明正在nesting);
当前nesting值(等于当前时间值减去nestingStarted时间值);
total总值(等于当前nesting值加上nestingTotal);
uint256 private nestingTransfer = 1;
function safeTransferWhileNesting(
address from,
address to,
uint256 tokenId
) external {
require(ownerOf(tokenId) == _msgSender(), "Moonbirds: Only owner");
nestingTransfer = 2;
safeTransferFrom(from, to, tokenId);
nestingTransfer = 1;
}
这里定义了一个safeTransferWhileNesting函数,NFT拥有者可以将正在nesting中的Moonbirds手动转移到另一个钱包地址,可用于owner进行NFT个人钱包转移或定向赠送,而不影响nesting值;
function _beforeTokenTransfers(
address,
address,
uint256 startTokenId,
uint256 quantity
) internal view override {
uint256 tokenId = startTokenId;
for (uint256 end = tokenId + quantity; tokenId < end; ++tokenId) {
require(
nestingStarted[tokenId] == 0 || nestingTransfer == 2,
"Moonbirds: nesting"
);
}
}
这里override了ERC721A标准中的_beforeTokenTransfers函数,使ERC721A标准的_transfer功能被调用时增加了一个nestingStarted必须等于0的条件,因此正在nesting中的Moonbirds无法被调用_transfer功能,也就无法在marketplace中进行交易,或被其他外部智能合约调用转移(比如即使误点了钓鱼偷盗网站,Moonbirds也无法被盗走,形成锁定与保护作用);
event Nested(uint256 indexed tokenId);
event Unnested(uint256 indexed tokenId);
event Expelled(uint256 indexed tokenId);
三个参数信息输出,用于将某一个tokenId的nest情况传至链下;
bool public nestingOpen = false;
function setNestingOpen(bool open) external onlyOwner {
nestingOpen = open;
}
智能合约owner启动nesting功能;
function toggleNesting(uint256 tokenId)
internal
onlyApprovedOrOwner(tokenId)
{
uint256 start = nestingStarted[tokenId];
if (start == 0) {
require(nestingOpen, "Moonbirds: nesting closed");
nestingStarted[tokenId] = block.timestamp;
emit Nested(tokenId);
} else {
nestingTotal[tokenId] += block.timestamp - start;
nestingStarted[tokenId] = 0;
emit Unnested(tokenId);
}
}
这里为Nesting开关功能函数,nestingStarted等于0时,调用此function即开启nesting并记录nestingStarted值为当前时间值;nestingStarted不等于0时,更新nestingTotal值(等于原总累积值加上当前时间值减去nestingStarted开始时间值),并将nestingStarted重置为0,即停止了nesting;
function toggleNesting(uint256[] calldata tokenIds) external {
uint256 n = tokenIds.length;
for (uint256 i = 0; i < n; ++i) {
toggleNesting(tokenIds[i]);
}
}
批量Nesting开关,可为一个array的tokenId进行toggleNesting函数调用;
function expelFromNest(uint256 tokenId) external onlyRole(EXPULSION_ROLE) {
require(nestingStarted[tokenId] != 0, "Moonbirds: not nested");
nestingTotal[tokenId] += block.timestamp - nestingStarted[tokenId];
nestingStarted[tokenId] = 0;
emit Unnested(tokenId);
emit Expelled(tokenId);
}
这里定义了expelFromNest功能函数,让智能合约管理员拥有关闭某个tokenId的nesting的权力,但已经nesting的记录值会得以保留。
总结:Moonbirds通过对智能合约进行原创开发,实现了NFT功能的创新,展示了项目方的技术能力;nesting功能的存在,不仅有效保护了NFT的安全,降低被盗风险,又在不移出owner钱包的基础上进行了某种类staking操作,增加了长期持有者的潜在收益可能,为钻石手提供动力,也在一定程度上抑制了卖盘,从而抬高了NFT二级市场价格。
JCONE.eth
2022/4/18
