Moonbirds Smart Contract Nesting 功能浅析

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