区块链最重要的功能,就是建立一种价值共识,而这个“共识”,主要基于“价值量化的能力”和“价值安全的过程”两个方面。先是“价值量化能力”:把一件事通过数字化的方式描述清楚,就是一个价值量化的过程。
其次是“价值安全的过程”:通过数字化的方式描述清楚后,还要保护数据不被篡改,并可以随时随地地查询。,这两个方面叠加起来,就形成了价值共识。所以,区块链在数据互通机制、信用体系的搭建上,必将发挥非常重要的作用。
后者定义如下:
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
此函数用于写入额外的信息,开发者需要自行定义 _extraData 函数以实现相关数据的写入。
此过程的核心函数为 _packOwnershipData ,其定义如下:
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask owner
to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags
.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
有了上述 _nextInitializedFlag 和 _nextExtraData 的补充和注释,相信读者可以理解 _packOwnershipData 的实现原理,简单来说,该函数使用 or 操作符拼接 owner 、 timestamp 和 flags 以实现最终的数据结构。显然,我们只需要构造以下部分作为flags输入,即可完成 _packOwnershipData 的构造:
// - [224] burned
// - [225] nextInitialized
// - [232..255] extraData
1
2
3
读者可以注意到 owner 、 timestamp 和 flags 均为 uint256 数据类型,所以直接使用 or 进行拼接是合适的
接下来设置 _packedAddressData 数据结构。此数据结构定义如下:
// Bits Layout:
// - [0..63] balance
// - [64..127] numberMinted
// - [128..191] numberBurned
// - [192..255] aux
mapping(address => uint256) private _packedAddressData;
mint 过程仅涉及 balance 和 numberMinted 两部分数据。所以设置较为简单,代码如下:
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
1
我们使用 ((1 << _BITPOS_NUMBER_MINTED) | 1) 构造(此处 _BITPOS_NUMBER_MINTED = 64 )出如下二进制数字 (以 16 进制表示):
0b10000001
1
使用 Python 运行 bin((64 << 1) | 1) 可以获得此结果
所以我们可以直接将数字与 balance 和 numberMinted 对齐相加。
在释放 Transfer 事件前,我们需要对 NFT 接受方的地址进行简单校验,即保证 NFT 接受方的地址不为 0 地址,校验代码如下:
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);