简述:
CPT255
让任何推特用户获得方便地发行NFT的能力,并将此NFT与多种社交软件绑定,实现Web3社交。
功能和关键特性描述: 推特用户通过其账号发行一款推特头像图片的KeyNFT
,将KeyNFT
用在TG
/Chatpuppy
等社交软件中;每款KeyNFT
总量255枚;每枚KeyNFT的价格为$(id-1)^\frac{5}{4}/k$ ETH;买入时免费;卖出时按VAT方式计费并支付给KeyNFT
的发行者,协议和推荐人;KeyNFT
满255个时拆分成总量约1万的可自由交易的TickNFT
,KeyNFT
持有者免费获得不等的TickNFT
。
特点:
- 总量有限。每款
KeyNFT
总量255
枚,每款TickNFT最多10703
枚。 - 价格平滑。采用$\frac{5}{4}$次幂,让价格更平滑,降低早期和晚期参与者之间成本差。
- 采用VAT(Value-added Tax)收费,收费更公平。
- 先内部交易后自由交易。内部交易的价格由智能合约确定,全部255枚
KeyNFT
铸造完成后,拆分并可自由交易。这种分阶段方案让NFT的冷启动更有保障。 - 资金池用于生态发展。在拆分后,销售
KeyNFT
的资金可用来推动运营,其中40%用于特别奖励。 - 使用
AA钱包(account abstration wallet)
,用户使用门槛低,更安全,有效防刷单,更加公平。
本文就CPT-201
协议的几个比较重要且复杂的技术问题解答如下。
1- KeyNFT的价格
1.1- KeyNFT的买入价格:
\(P_b=\frac{(id - 1)^\frac{5}{4}}{k}\) \((id > 0)\)
其中id
为KeyNFT
的序号,用户购买一个KeyNFT
,id
会加一,用户卖出一个KeyNFT
,id
会减一。
1.2- KeyNFT的买出价格为:
\(P_s=\frac{(suply - 1)^\frac{5}{4}}{k}\) \((supply > 1)\)
supply
为当前KeyNFT
的总量,因为不允许卖出最后一个KeyNFT
,所以卖出时的公式中supply>1
。
1.3- 价外税(费)
所有费用和VAT都是价外税(费),即:
- 购买时,用户支付金额 = $P_b + BuyFee$,BuyFee暂定为2%,所以实际支付金额 = $1.02*P_b$
- 买出时,需要在上述$P_s$基础上扣除VAT后,再给到卖出方,即 $实际所得 = P_s - (P_s - P_b) * VATRate$,VATRate暂定为30%,所以: $实际所得 = P_s - (P_s - P_b)*0.7$(VAT详细内容见下文)
1.4- 销售总额
-
当所有
KeyNFT
被销毁时,协议内用于回购的资金池归为0。 -
当所有
KeyNFT
被铸造完,协议内用于回购的总资金为:
\(\sum\frac{(id - 1)^\frac{5}{4}}{k}\) \((id>0)\)
1.5- 关于系数$k$和NFT最大发行量
经过测算,协议设置:
- $k=5000$
- 每款KeyNFT的最大数量为
255
枚(这也是本协议命名为CPT255
的原因)
在这两个参数作用下:
- 初始化第1个NFT时,价格为$\frac{(1-1)^\frac{5}{4}}{5000}$ = 0;
- 在购买第2个NFT时,价格为$\frac{(2-1)^\frac{5}{4}}{5000}$ = 0.0002 ETH;
- 在购买第50个NFT时,价格为$\frac{(50-1)^\frac{5}{4}}{5000}$ = 0.025928 ETH;
- 在购买第100个NFT时,价格为$\frac{(100-1)^\frac{5}{4}}{5000}$ = 0.062456 ETH;
- 在购买第200个NFT时,价格为$\frac{(200-1)^\frac{5}{4}}{5000}$ = 0.149485 ETH;
- 在购买第255个NFT时,价格为$\frac{(200-1)^\frac{5}{4}}{5000}$ = 0.202802 ETH;
1.6- 价格曲线:
1.7- 价格变化率曲线:
价格涨幅呈现一开始很高(如在购买第3个KeyNFT
时的价格是0.000476ETH,比第2个高138%;之后涨幅降低,从第65个KeyNFT
开始,单个涨幅小于2%;从第128个KeyNFT
开始,单个涨幅小于1%,第255个KeyNFT
的价格比第254个高0.5%。
价格变化%公式:
\[\delta = (\frac{id-1}{id - 2})^\frac{5}{4} - 1\] \[id > 1\]图表如下:
2- 费用和VAT(Value-Added Tax)
2.1 购买费用
在购买KeyNFT
时,会在上述计算得出的价格基础上增加2%
的费用,该费用会立即打到用户的推荐人账户。
2.2 VAT的计算
在卖出KeyNFT
时,会依据买入时的价格和卖出价格之间的利润收取VAT,如果亏损,即买入价格>=卖出价格
时,则不收取任何VAT。
VAT计算公式:
\(VAT=(P_s - P_b)*R\)
R暂定为30%
举例:
Alice买入第10个NFT,价格为$(10-1)^\frac{5}{4}/5000$=0.003118 ETH,然后又买入第16个NFT,价格为$(16-1)^\frac{5}{4}/5000$=0.005904 ETH。
当第40个NFT被购买,即价格为$(40-1)^\frac{5}{4}/5000$=0.019492 ETH 时,Alice决定卖出其中一个NFT(合约会自动卖出ID最大的NFT,因为这个成本最高,可以降低VAT),因此,卖出的这个NFT的id为16,这个NFT的毛利润为0.019492 - 0.005904 = 0.013588 ETH
,她将支付0.013588 * 30% = 0.0040764 ETH
作为VAT,实际获得0.019492 - 0.0040764 = 0.0154156 ETH
。
采取VAT方式,比采取根据交易金额收取费用更公平。但是在很多场景下,因为无法确定购买成本,很难采用VAT方式,下文2.6节
将介绍本协议获取购买成本的Tagged NFT
解决方案。
2.3- VAT率与费用率之间关系
来比较一下VAT和常规的根据交易金额收取费用的区别:
假设毛利润率为$P$,VAT率为$R_v$,依据销售额征收的费用率为$R_f$,则
\[\frac{R_f}{R_v} = \frac{P}{P+1}\]如果要让VAT等于依据销售额征收的费用,则:$(P+1)R_f = PR_v$,得到:
\[P = \frac{R_f}{R_v-R_f}\]如果,$R_v$ = 30%,$R_f$ = 10%,则$P = 50%$,即如果毛利润为50%的话,征收30%的VAT,相当于依据销售额征收10%的费用。当毛利润率高于50%时,VAT会高于10%的费用,但当毛利润低于50%时,VAT会低于10%的费用。
在这种情况下,如果用户购买后后悔,想立即卖出,则无需支付VAT,因为买卖价格一致。
2.4- 实际利润率
在征收VAT后,实际利润率$P’$为: \(P' = P*(1 - R_v)\)
如用户在卖出时的税前毛利润率为200%,则其实际利润率为200%*(1-30%)=140%
。
2.5- VAT的分配
VAT分配暂定如下:
- NFT发行者,获得税前毛利润的15%
- 推荐人,获得睡前毛利润的9%
- 协议,获得税前毛利润的6%
2.6- 记录每个NFT的购买价格 - Tagged ERC1155
为了实现上述在出售时,精确的计算毛利润以及VAT,需要知道每个KeyNFT的购买成本。根据前几节介绍,我们知道购买成本取决于KeyNFT的 ID,所以这个问题变成了如何知道所拥有的每个KeyNFT的ID。
ERC1155
标准把不同NFT放在了一个合约里,每个NFT拥有从1开始的ID,但是ERC1155
并没有实现如何确定某个地址拥有哪些ID,或者某个ID归属于哪个地址。
为了解决这个问题,我们在ERC1155
基础上,扩展了名为Tagged ERC1155
的新方案。
因为限定了每个NFT最多不超过255
个,所以,可以使用一个uint256
类型的数值来确定用户拥有的NFT的ID。
$\underbrace{a_{255},a_{254},a_{253},a_{252},a_{251},a_{250},a_{249},a_{248},a_{247},\cdots,a_{6},a_{5},a_{4},a_{3},a_{2},a_1}_{255 bits}$
当$a_n=1$时,说明拥有该位置的KeyNFT,当$a_n=0$时,不拥有。
2.6.1 数据结构
在合约里,我定义了如下数据结构,用来保存拥有的NFT的ID:
struct ID {
uint256 a; // 代表#1-#255 KeyNFT
}
mapping(uint32 => address => ID) nftIds
如果NFT数量比较多,可以进一步扩展结构中的参数。
2.6.2 数据解析
例如,当nftIds.a = 5
,即二进制数0b0101
时,说吗该用户拥有第#1,#3
号NFT。
再例如,当nftIds.a = 4718592
,即二进制数0b10010000000000000000000
时,说明该用户拥有第#20,#23
号NFT。
来个复杂点的,当nftIds为{a: 104018, b: 846747115870232577}
,即a=0b11001011001010010
,b=101111000000010000000000010000000000000010000010000000000001
,根据a值,说明该用户拥有第#2,#5,#7,#10,#11,#13,#16,#17
号NFT,根据b值,说明该用户还拥有第#257,#270,#276,#291,#303,#311,#312,#313,#314,#316
号NFT,合在一起,即是该用户所拥有的NFT,一共有18个。
以下是用于解析两个unit256
数值的solidity
智能合约代码:
function parse() public view returns(uint16[] memory pos, uint16 sum) {
ID memory id = nftIds[msg.sender];
pos = new uint16[](totalSupply());
uint16 i = 1;
for (i = 1; i <= 256; i++) {
if(id.a == 0) break;
if(id.a % 2 == 1) pos[sum++] = i;
id.a = id.a / 2;
}
}
该方法返回两个参数,第一个是位置的数组,第二个是拥有nft的总量。
2.6.3 防止ID重复
为了防止重复买入相同ID的NFT,需要设置一个mapping(uint16 id => address) nftAddresses;
,用来记录某个KeyNFT
的所有者,当该值为0x0
时,说明不被任何人拥有。
通过以下exist
合约方法,判断是否已经被拥有。
function exist(uint16 id) public view returns(bool) {
return nftAddresses[id] != address(0x0);
}
2.6.4 买入NFT时
当购买一个KeyNFT
时,用以下add
方法用来添加买入的KeyNFT
的ID:
function add(uint16 id) public {
nftIds[msg.sender].a += 1 << (id - 1);
nftAddresses[id] = msg.sender;
}
上述代码中,使用1<<n
取代2^n
,以提高计算效率,下同。
2.6.5 卖出NFT时
当卖出一个NFT时,用以下remove
方法用来删除卖出的KeyNFT
的ID:
function remove(uint16 id) public {
nftIds[msg.sender].a -= 1 << (id - 1);
nftAddresses[id] = address(0x0);
}
3- KeyNFT的拆分
3.1 KeyNFT的转让
KeyNFT
不可互相转让(在智能合约中,将transfer
和transferFrom
等方法的权限关闭),只能通过本智能合约按照协议规则买(即mint
)和卖(即burn
)。在KeyNFT
阶段,KeyNFT
可以在钱包中查看,可以上架OpenSea
等支持ERC1155
的NFT交易所,但是无法转让和交易。
KeyNFT
的发行人可随时将转让状态从“不可转让”调整为“可转让”,但是一旦设为“可转让”,无法再设回“不可转让”,可转让的NFT即TickNFT
。
在KeyNFT
变为“可转让”的TickNFT
后,原KeyNFT
持有人可调用ReMint
合约方法,将手上的KeyNFT
拆分。
拆分规则和拆分后的TickNFT
总量,见下文。
3.2 拆分时TickNFT
的数量和分配
在所有KeyNFT被铸造出,会进行拆分,并根据KeyNFT
的持有以及推荐情况分配拆分后的TickNFT
。
3.2.1 获得TickNFT方法
所有KeyNFT
持有人需要与智能合约进行交互获取TickNFT
。
3.2.2 获得的TickNFT数量:
- 如果没有推荐过任何人:一个
KeyNFT
可获得35个TickNFT
; - 如果推荐
n
个人入群:则可获得35+5*n
个TickNFT
,即每推荐一个,多获得5
枚。
3.2.3 TickNFT总量
TickNFT
总量计算公式:
其中:
- T:
TickNFT
总量 - B:每个人都能获得的基础
TickNFT
数量 - C: 每推荐一个人,奖励的
TickNFT
数量 - K:
KeyNFT
总量,即255
枚 - m:没有推荐过任何人,且自己不是被群内人推荐的人数
- n:推荐过其他人入群的人数
上述所有参数皆为正整数,不能出现小数和负数。
从上述公式中可以看出:当C=0
,也就是没有推荐奖励时,TickNFT
的总量固定。但是我们的情况没有那么简单。
为防止推荐人得到的奖励比没有推荐的人获得的少,这里假设B=i*C
,上述公式变为:
\(T = (K*i + K - m - n)*C\)
假设:B=35,C=5,i=7,m=50,n=20,则T=255*35+(255-50-20)*5=9850枚
TickNFT
数量一旦确定,既无法增发,也无法销毁,只能转让和交易。
3.2.4 TickNFT总量的范围
因为m
和n
两个值是无法固定的,会随着社区的发展而变化,所以TickNFT
会存在一个范围。
如果K
个KeyNFT
的持有人中没有任何推荐人,则m=K,n=0
,这时TickNFT
的总量为:T=K*B= K*i*C
。
如果K
个KeyNFT
持有人中所有人都是被一个人推荐的,则n=1,m=0
,这时TickNFT
的总量为:T=K*B+(K-1)*C=(K*i + K - 1)*C
。
所以,TickNFT
的范围为:
or
\[T \in [K*B, K*B + (K - 1)*C]\]最大和最小之间相差:(K-1)*C
,因为C
不可能为0
,所以这个差额是永远存在的。
在本案中,C=5,i=7,所以TickNFT
的范围为[8925, 10195]
。
3.3 销售KeyNFT的资金的使用与分配
因为每个NFT的买入价格为
\[P_b=\frac{(id - 1)^\frac{5}{4}}{k}\]且费用和VAT都是价外税(费),所以:
-
当所有NFT全部销毁时,协议内用于回购的资金池为0。
-
当
255
个NFT全部铸造完,协议内收到的销售总额为:
因为:id ∈ [1, 255], k=5000,所以全部铸造完成时,合约中将有约23
个ETH(22995561951692318400Wei)
该笔资金用途:
8.75ETH
,用于特别奖励,见下面;7.25ETH
,KeyNFT发行人;7ETH
,发展基金;
4- 特别奖励
KeyNFT
的持有人除了获得TickNFT
外,还能参与抽奖,奖金来自于KeyNFT
销售金额的38%,即8.75ETH
,这笔奖金按以下方案分给3
个KeyNFT
持有人:
- #1: 5ETH
- #2: 2.5ETH
- #3: 1.25ETH
获奖概率根据购买价格加权:
\[r = \frac{P_b}{S}*3\] \[P_b: 购买价格,S: 销售总额,即23ETH\]举例:
- 平均中奖概率:3/255=1.18%;
- 第255个KeyNFT拥有者,获奖概率2.65%;
- 第204个KeyNFT拥有者,获奖概率2%;
- 第162个KeyNFT拥有者,获奖概率1.5%;
- 第134个KeyNFT拥有者,获奖概率1.18%,平均水平;
- 第118个KeyNFT拥有者,获奖概率1%;
- 第68个KeyNFT拥有者,获奖概率0.5%;
- 第33个KeyNFT拥有者,获奖概率0.2%;
- 第10个KeyNFT拥有者,获奖概率0.04%;
4.1- 抽奖智能合约
为了公平的抽奖,现将合约中的随机数抽奖代码介绍如下:
4.1.1 随机数
随机数种子使用keccak256(abi.encodePacked(block.timestamp, msg.sender, nonce))
,即区块链当前时间戳,发送人和nonce。
nonce
是一个自增值,所以这个函数是一个改变状态的函数,而不是pure
或view
函数。
function getRandom() public returns(uint256) {
uint256 rand = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, nonce))) % 1e8;
nonce++;
return rand;
}
4.1.2 权重Map
bonusProbilityWeight
是一个根据$r = \frac{P_b}{S}$,每个ID中奖概率的帕累托累计Mapping。
mapping(uint16 id => uint256 weight) public bonusProbilityWeight;
function initialProbilityWeight() internal {
uint256 weightSum = 0;
for(uint16 i = 1; i < cap + 1; i++) {
weightSum += priceTable[i];
bonusProbilityWeight[i] = weightSum * 1e8 / maxRaised;
}
}
4.1.3 获得中奖的ID
function whoIsLucky() public returns(uint16 i) {
uint256 rand = getRandom();
for(i = 1; i < cap + 1; i++) {
if(rand < bonusProbilityWeight[i]) break;
}
}
4.1.4 ID分布模拟
根据以上方法,在模拟了1000
次后,ID的分布图如下:
按模拟数据,可知:
|ID范围|中奖概率|平均概率|
|—|—|–|
|1~50|2.4%|0.048%|
|51~100|9.6%|0.192%|
|101~150|18.6%|0.372%|
|151~200|26.2%|0.524%|
|201~250|38%|0.76%|
|251~255|5.2%|1.04%|
考虑到有三次中奖机会,所以上述概率需要再乘以3。
5- 推荐
5.1 推荐规则
-
所有发行NFT的用户可称为推荐人,推荐码在Dapp中获取。
-
被推荐人在买卖KeyNFT前必须绑定推荐人,否则无法买卖。
-
推荐人关系一旦绑定,无法解除或变更。
-
被推荐人购买
KeyNFT
时,推荐次数+1;当被推荐人卖出KeyNFT
时,推荐次数-1。
5.2 推荐人的权益
- 在被推荐人购买
KeyNFT
时,获得购买金额2%
的推荐奖; - 在被推荐人出售
KeyNFT
时,获得VAT的30%,即买卖差价的9%; - 在用户提取拆分后的
TickNFT
时,推荐人获得TickNFT
奖励,即:每推荐一个,多获得5
枚TickNFT;