FLAPixel 金库是如何工作的?
FLAPixel 是一个Flap 税收金库的 ERC-721 NFT 金库工厂。Token 交易产生的 BNB 税收进入 Vault 后,会按照创建金库时填写的比例拆成两部分:
- 分红池:给当前 NFT 持有人领取 BNB。
- 地板价池:托底 NFT,用户可以把 NFT 卖回金库并销毁。
NFT 图像是链上生成的。每张 NFT 在合成时固定自己的图像 seed,只有所有者地址跑马灯会读取当前 owner,因此转账NFT后跑马灯地址会变化。
核心流程
- 用户买卖 Token,Flap 税收流程把 BNB 分到 Vault。
- Vault 的
receive()收到 BNB。 - Vault 按
dividendSharePercent / 分红比例和floorSharePercent / 地板价比例拆分税收。 - 有 NFT 时,分红部分进入分红账本;每个地址按当前 NFT 余额作为权重。
- 地板价部分进入
floorPool / 地板价池,用于用户卖回 NFT。 - 用户用 Token 合成 NFT,Token 会转入
DEAD地址销毁。 - 用户可以调用
claim()领取自己当前地址下所有 NFT 权重对应的 BNB 分红。 - 用户可以调用
sellToVault(tokenIds)按当前地板价批量卖给金库,卖回的 NFT 会被销毁。
创建参数说明
| 参数 | 含义 | 填写建议 |
|---|---|---|
NFTName | NFT 系列名称 | 例如 FLAPixel NFT |
NFTSymbol | NFT 符号 | 例如 FPIX |
maxNFTSupply / NFT 最大总量 | NFT 最大总量 | 必须大于 0,且满足兑换总量限制 |
initialFloorNFTs / 首次税收托底 NFT 数量 | 首次税收托底 NFT 数量 | 必须 >= 1,且 <= maxNFTSupply / NFT 最大总量 |
tokenCostPerNFT / 每张 NFT 消耗 Token 数量 | 每张 NFT 需要消耗多少 Token | 用户支付后 Token 会销毁 |
dividendSharePercent / 分红比例 | 进入 NFT 分红池的税收比例 | 填 0-100,例如 50 代表 50% |
floorSharePercent / 地板价比例 | 进入 NFT 地板价池的税收比例 | 填 0-100,必须和分红比例相加等于 100 |
artSchema | NFT 图像 schema 合约 | 填 零地址使用默认 FLAPixel;填外部合约地址使用自定义图像 |
关键限制
比例公式:
dividendSharePercent + floorSharePercent = 100
进入 NFT 分红池的税收比例 + 进入 NFT 地板价池的税收比例 = 100%
兑换上限公式:
maxNFTSupply * tokenCostPerNFT <= 1,000,000,000
NFT 最大总量 * 每张 NFT 消耗的 Token 数量 <= Token 总量 1,000,000,000
示例只是在说明上限,不代表必须把 10 亿 Token 全部用满。只要乘积小于或等于 10 亿都允许。
| NFT 总量 | 每张消耗 Token | 总消耗 | 是否允许 |
|---|---|---|---|
| 100 | 1,000 | 100,000 | ✅ 允许 |
| 1,000 | 10,000 | 10,000,000 | ✅ 允许 |
| 20,000 | 50,000 | 1,000,000,000 | ✅ 允许 |
| 20,000 | 100,000 | 2,000,000,000 | ❌ 不允许 |
| 100,000,000 | 10 | 1,000,000,000 | ✅ 允许 |
| 100,000,001 | 10 | 1,000,000,010 | ❌ 不允许 |
initialFloorNFTs / 首次税收托底 NFT 数量
地板价公式:
floorPrice = floorPool / max(activeNFTSupply, initialFloorNFTs - totalBurned)
NFT 地板价 = 地板价池里的 BNB / max(当前还存在的 NFT 数量, 首次税收托底 NFT 数量 - 已通过金库卖回销毁的 NFT 数量)
它的作用是防止早期 NFT 数量很少时,第一张 NFT 直接吃掉过高地板价。
例如:
maxNFTSupply / NFT 最大总量 = 1000initialFloorNFTs / 首次税收托底 NFT 数量 = 100floorPool / 地板价池 = 10 BNB- 当前只铸造了 1 张 NFT
此时不是:
floorPrice = 10 BNB / 1
NFT 地板价 = 地板价池里的 10 BNB / 当前 1 张 NFT
而是:
floorPrice = 10 BNB / 100 = 0.1 BNB
NFT 地板价 = 地板价池里的 10 BNB / 首次税收托底 100 张 NFT = 0.1 BNB
通过 sellToVault(tokenIds) 卖回并销毁的 NFT 会消耗对应托底份额。例如 initialFloorNFTs / 首次税收托底 NFT 数量 = 100,已经通过金库卖回销毁 10 张,则剩余托底份额是 90。
等当前还存在的 NFT 数量超过剩余托底份额后,会按当前还存在的 NFT 数量计算。
玩法模式
这套金库不是单纯"发一张 NFT",而是把 NFT 做成项目税收的一层可视化权益。创建者可以决定税收更偏向即时分红,还是更偏向 NFT 地板价托底。
默认最容易理解的是 50% / 50%:一半进入分红,一半进入地板价池。这样 NFT 持有人既能看到 BNB 收益,也能看到金库对 NFT 的托底在积累。
50% 分红,50% NFT 地板价
填写:
dividendSharePercent / 分红比例 = 50
floorSharePercent / 地板价比例 = 50
- 一半税收进入 NFT 分红池,当前 NFT 持有人可以领取 BNB。
- 一半税收进入 NFT 地板价池,逐步形成卖回金库的托底价格。
- NFT 不是只看图片,而是同时承载分红、地板价、销毁退出和纯链上图像。
交易越活跃,Vault 收到的 BNB 越多,NFT 的分红和地板价池都会同步增长。用户持有 NFT 时可以领取收益;需要退出时,也可以按金库地板价卖回并销毁。
100% 分红,0% NFT 地板价
填写:
dividendSharePercent / 分红比例 = 100
floorSharePercent / 地板价比例 = 0
- 所有进入 Vault 的 BNB 税收都分给 NFT 持有人。
- 每张 NFT 是一份分红权重。
- 一个人持有 10 张 NFT,就有 10 份分红。
- NFT 更接近"BNB 收益凭证"。
如果还没有任何 NFT 被铸造,分红税不会留给第一张 NFT 直接领取,而是进入 buyback burn 队列,通过 Flap Portal 回购销毁 Token。
0% 分红,100% NFT 地板价
填写:
dividendSharePercent / 分红比例 = 0
floorSharePercent / 地板价比例 = 100
玩法:
- 所有进入 Vault 的 BNB 税收都进入 NFT 地板价池。
- NFT 持有人没有 BNB 分红可领。
- NFT 的价值主要体现在可卖回金库的地板价。
- 用户卖给金库后,NFT 会销毁,NFT 存量减少。
税收不断进入地板价池,卖回金库的 NFT 会被销毁,剩余 NFT 数量会减少。它不强调持续领取 BNB,而是强调"有限 NFT + 税收托底 + 回收销毁"的结构。
早期没有 NFT 时,税收也会进入地板价池,但地板价会按 initialFloorNFTs / 首次税收托底 NFT 数量 摊开,避免第一张 NFT 直接按全部池子卖出。
合成 NFT 的数量计算
mintNFTWithTokenAmount(tokenAmount / 传入 Token 数量) 要求:
tokenAmount % tokenCostPerNFT == 0
传入的 Token 数量 % 每张 NFT 消耗的 Token 数量 = 0
也就是说,传入的 Token 数量必须刚好能整除单张 NFT 价格。
合成数量公式:
mintQuantity = tokenAmount / tokenCostPerNFT
可合成 NFT 数量 = 传入的 Token 数量 / 每张 NFT 消耗的 Token 数量
单次合成数量必须满足:
mintQuantity <= MAX_MINT_BATCH
单次最多合成 100 张 NFT
示例:
- 每张 NFT 需要
1,000,000Token。 - 输入
5,000,000Token,可以合成 5 张 NFT。 - 输入
4,500,000Token,不能合成 4.5 张,会直接失败。
分红如何计算
分红按地址 NFT 余额权重结算,不按用户持有的 NFT 列表逐张循环。
公式:
accDividendPerNFT += dividendAmount * PRECISION / activeNFTSupply
pending(user) = pendingRewardOf[user] + NFTBalance(user) * (accDividendPerNFT - rewardDebtOf[user]) / PRECISION
如果某个地址持有 10 张 NFT,它就有 10 份分红权重;持有 100 张 NFT,就有 100 份分红权重。
用户调用 claim() 时,会领取当前地址拥有的所有 NFT 的待领取 BNB。
NFT 转账前会先把旧 owner 和新 owner 的分红账本结算到各自地址,不会强制转出 BNB。转出成功后,旧收益留给旧 owner,新收益归新 owner。
卖回金库如何计算
用户调用:
sellToVault(tokenIds)
tokenIds 是 NFT 编号数组。卖 1 张时传 [1],卖多张时传 [1,2,3]。单次最多卖回 100 张。
合约会:
- 检查数组不为空,且数量不超过
MAX_SELL_BATCH / 单次卖回上限。 - 检查数组里的每个 NFT 都属于当前调用者。
- 先结算当前调用者地址下所有 NFT 的待领取分红。
- 在本次交易开始时读取一次
floorPrice() / NFT 地板价,作为本次卖回的单张快照价格。 - 计算总卖回金额:
本次单张地板价 * tokenIds.length。 - 从
floorPool / 地板价池一次性扣除总金额,并支付 BNB 给用户。 - 销毁数组里的所有 NFT。
- 本次卖回不会改变其他已经铸造 NFT 的主体图像。
同一笔批量卖回里,每张 NFT 的单张价格一致。例如当前地板价是 1 BNB:
sellToVault([1]) = 1 BNB
sellToVault([1,2,3]) = 3 BNB
sellToVault([1...100]) = 100 BNB
卖回本身只是按当前地板价赎回并销毁 NFT。卖回会减少当前还存在的 NFT 数量,并消耗对应托底份额;只有新的地板价税收进入 floorPool / 地板价池 后,地板价池余额才会继续增加。
只有调用 sellToVault(tokenIds) 才会从金库拿到地板价 BNB。用户直接把 NFT 转到 DEAD 或其他不可控地址,只是普通 ERC-721 转账,不会触发地板价赎回,也不会更新金库的 totalBurned / 已销毁NFT 统计。
没有 NFT 时税收怎么处理
没有 NFT 时,分红池没有接收对象,所以分红税不会留给第一张 NFT 直接领取。
处理方式:
- 分红税部分:进入
pendingBuybackBNB,达到阈值后通过 Flap Portal 回购并销毁 Token。 - 地板价税部分:进入
floorPool / 地板价池,按initialFloorNFTs / 首次税收托底 NFT 数量摊开计算地板价。
当前 buyback burn 规则:
- 小于
0.01 BNB时先累计。 - 大于等于
0.01 BNB时尝试执行。 - 单次最多执行
1 BNB。 - 回购销毁统计按
DEAD地址实际增加的 Token 数量记录。 - 如果 Flap Portal swap 失败,不 revert 收款,金额保留到下一次继续尝试。
图像 Schema(自定义 NFT 图像)
开发者想自定义 NFT 图像时,正式规范就是实现 IPixelArtSchema。
标准接口:
interface IPixelArtSchema {
function schemaVersion() external view returns (uint256);
function schemaName() external view returns (string memory);
function canvas(uint256 seed, uint256 tokenId) external view returns (string memory svgFragment);
}
interface IPixelArtSchemaTraitsV1 {
function attributes(uint256 seed, uint256 tokenId) external view returns (string memory jsonAttributeObjects);
}
核心规则:
schemaVersion()必须返回大于 0 的整数。schemaName()不能为空。canvas(seed, tokenId)只返回 SVG fragment,不要返回完整<svg>。- 画布按
512 x 512来设计。 - 图像不强制使用像素网格;可以使用
rect、circle、path、g等 SVG 元素自由绘制。 attributes(seed, tokenId)是可选接口,返回 JSON attribute 对象片段,不带外层数组。- 外部 schema 的图像和属性都会通过
staticcall读取,不能修改 Vault 状态。 canvas()fragment 最大9,500 bytes,render gas limit 为1,800,000。attributes()返回值最大4,000 bytes,attributes gas limit 为400,000。