合约分层与权限
FastX Node 链上合约的替换边界与角色范围。这是一份说明,不是控制台功能,改这个文件即可更新本页。
判断一个合约能不能换掉,只有一条标准:它自己攒的状态,丢了要不要紧。
一、基础设施层 · 不能替换
节点资产和推荐关系是长生命周期事实,换掉就没了,无法重建。
| 合约 | 攒了什么 | 为什么不能换 |
|---|---|---|
FastXNodeNFT |
节点资产、生命周期状态、算力、维护期 | 节点本身就是它。换掉等于所有人的节点作废 |
ReferralRegistry |
账户激活、推荐边、推荐码注册表、节点归因 | 推荐关系是事实层,链下无法重建 |
FXNW |
固定总量,构造时一次铸完,无任何参数 | 换合约等于换代币,那是迁移不是替换 |
二、可迁移层 · 能换,但必须先迁状态
这三个能换,但各自攒了一份丢了要出事的状态。换之前先想清楚这份状态怎么办。
| 合约 | 留存状态 | 不迁的后果 |
|---|---|---|
NodeMintGateway |
mintedOrigins,结算侧的幂等键 |
新表是空的,旧 originId 重放会重复铸造 |
MiningSettlement |
锚点哈希链,每条锚点链到前一条 | 新部署从 seq 0、prev 为 0 开始,链断在换合约那一刻。合约没有重置能力,这是设计如此 |
FXNWClaim |
托管的 FXNW、各期 Merkle 根、已领记录 | 钱留在旧合约;已领记录丢失等于开了重复领取的口子 |
AICClaim |
托管的 FXNW、每个钱包的已领累计额 | 换之前先 recover 把钱取走;累计额丢了,已经领过的人能按同一张签名再领一次 |
三、可替换层 · 换掉就换掉
自己只存配置,事实都写在 NFT 和 Registry 上。重连角色、重设配置即可。
| 合约 | 自己的状态 | 说明 |
|---|---|---|
NodeSale |
各类型售卖配置、已售计数 | L1 预售入口 |
NodeDirectSale |
售卖配置、burnBps、treasury、vault | USDT / FXNW 直购入口 |
NodeCompose |
composeEnabled | L2 合成 L3 |
NodeMaintenance |
各类型费率、treasury | 维护期写在 NFT 上,不在它这里。开发环境已实际换过一次 |
NodeComposeVoucher |
只有 signer | 自己不铸也不记账,originId 唯一性在网关。换掉只需重授网关角色、重设签名者 |
替换时必须重连的角色
新合约授上,旧合约同时撤掉。不撤旧的,两份合约都能写同一份事实,出问题时分不清来源。
| 新合约 | 需要的角色 |
|---|---|
NodeSale / NodeDirectSale |
NFT 的 MINTER_ROLE;Registry 的 ATTRIBUTION_RECORDER_ROLE |
NodeCompose |
NFT 的 MINTER_ROLE 和 COMPOSER_ROLE;Registry 的 ATTRIBUTION_RECORDER_ROLE |
NodeMintGateway |
NFT 的 MINTER_ROLE;Registry 的 ATTRIBUTION_RECORDER_ROLE |
NodeMaintenance |
NFT 的 MAINTENANCE_ROLE |
各合约的角色与权限范围
所有角色都由 DEFAULT_ADMIN_ROLE 管理。撤销 DEFAULT_ADMIN_ROLE 是唯一不可逆的操作:它没有别的来源,最后一个持有者被撤销后没有人能再授予它。
FastXNodeNFT
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤所有角色、改各类型算力、改元数据 URI、暂停 | 多签 |
MINTER_ROLE |
铸造节点 | 各销售与合成合约,不给人 |
NODE_ADMIN_ROLE |
节点管理操作 | 运营 |
MAINTENANCE_ROLE |
写 maintenanceUntil |
仅 NodeMaintenance |
COMPOSER_ROLE |
消耗节点用于合成 | 仅 NodeCompose |
改各类型算力只影响之后铸造的节点,已铸节点的算力永久固定。
ReferralRegistry
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色、改激活签名者与登记费、开关自注册、启停推荐码、暂停 | 多签 |
CHANNEL_MANAGER_ROLE |
注册 Root 码与渠道码、激活渠道码 | 运营 |
ACCOUNT_CODE_REGISTRAR_ROLE |
链上登记账户推荐码 | 仅 registrar worker |
ATTRIBUTION_RECORDER_ROLE |
记录节点归因 | 各销售与合成合约 |
停用推荐码不剪已有的推荐边,只是不能再用它建立新的归属。
NodeSale · NodeDirectSale
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色 | 多签 |
SALE_OPERATOR_ROLE |
改售价与供应上限、改签名者、暂停 | 多签 |
TREASURY_ADMIN_ROLE |
改收款地址 treasury / vault | 多签 |
NodeDirectSale 的 USDT 与 FXNW 是两条独立通道,各自定价,价格之间没有换算关系。任一价格设为 0 即关闭该通道。
NodeMaintenance
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色 | 多签 |
MAINTENANCE_OPERATOR_ROLE |
改费率、赠送维护期、暂停 | 运营 |
TREASURY_ADMIN_ROLE |
改收款地址 | 多签 |
赠送维护期不收费,直接给算力。
NodeMintGateway
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色 | 多签 |
GATEWAY_OPERATOR_ROLE |
铸造 L2 节点 | 仅铸造热钱包,别给第二个地址 |
GATEWAY_ADMIN_ROLE |
改每日铸造上限、暂停 | 多签 |
每日上限就是铸造热钱包被盗时一天的损失上界。铸造钱包在 NFT 与 Registry 上不应有任何角色。
NodeCompose
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色 | 多签 |
COMPOSE_OPERATOR_ROLE |
开关合成、暂停 | 运营 |
NodeComposeVoucher
用户自助合成的入口。合约自己不铸造,它持有 NodeMintGateway 的 GATEWAY_OPERATOR_ROLE,调 mintComposed。每日上限、originId 唯一性、归因全在网关那边,这里不留第二份状态。
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色、setSigner、unpause |
多签 |
PAUSER_ROLE |
pause |
运维 EOA |
暂停与恢复不对称:运维一笔交易就能停,恢复要多签。熔断时不能等一轮签名。
它在网关上还必须持有 GATEWAY_OPERATOR_ROLE,这是唯一不可或缺的外部依赖,也是部署最容易漏的一步:漏了之后本合约每一项读数都正常,但每一笔赎回都 revert。「合成凭证」那一页把这个检查放在最上面。
暂停凭证合约只挡自助赎回,worker 代铸那条路径不受影响;两条都要停就连网关一起暂停。
AICClaim
AIC 兑换 FXNW 的链上领取。托管 FXNW,按签名里的累计额付款。
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色、setSigner、unpause、recover |
多签 |
PAUSER_ROLE |
pause |
运维 EOA |
同样是不对称暂停。recover 只能在暂停状态下执行,金额上限合约不管,由多签自己遵守。
MiningSettlement
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色 | 多签 |
PUBLISHER_ROLE |
发布结算锚点 | 仅结算热钱包 |
无任何参数,也不能暂停。只能追加,不能改历史;更正靠追加新版本。
FXNWClaim
| 角色 | 能做什么 | 谁该持有 |
|---|---|---|
DEFAULT_ADMIN_ROLE |
授撤角色 | 多签 |
PUBLISHER_ROLE |
发布每期 Merkle 根 | 仅提现热钱包 |
CLAIM_ADMIN_ROLE |
暂停领取 | 多签 |
没有提取函数。注资就是向合约地址转 FXNW。停发下一期加暂停,损失上界是一个注资周期。
FXNW
由项目方部署,不在本项目的角色体系内。见文末「关于 FXNW」。
后端签名者
四个合约各自信任一个后端签名地址,角色不同、函数名也不同。「签名者」那一页把四个放在一起,因为一把 key 泄露时要问的是全部四个。
| 合约 | 读 | 写 | 需要的角色 | 签的是什么 |
|---|---|---|---|---|
ReferralRegistry |
activationSigner |
setActivationSigner |
DEFAULT_ADMIN_ROLE |
账户激活授权 |
NodeSale |
signer |
setSigner |
SALE_OPERATOR_ROLE |
L1 预售购买授权 |
AICClaim |
signer |
setSigner |
DEFAULT_ADMIN_ROLE |
AIC 兑换的链上领取 |
NodeComposeVoucher |
signer |
setSigner |
DEFAULT_ADMIN_ROLE |
自助合成凭证 |
合约只认当前这一个地址,换掉之后旧签名立即作废,没有宽限期。泄露时的顺序是先暂停、再换签名者、最后恢复。
换掉的代价各不相同:AIC 签的是累计额,谁也不会少领;激活和预售的旧授权作废后用户重新取一份即可;凭证作废后重新 GET 一份,originId 不变所以不会重复铸造。
这些角色不预设在多签里。 按钮是灰是亮,取决于当前连接的钱包在链上是否真的持有对应角色;持有就直接发交易,不持有才给出可粘贴的交易数据。项目方不设多签时同样能用。
常量 · 改就要重新部署
这些是编译期常量,没有 setter,构造函数也不收。改动意味着重新部署加公告。
| 常量 | 值 | 位置 | 含义 |
|---|---|---|---|
REQUIRED_COUNT |
100 | NodeCompose |
合成一个 L3 所需的 L2 数 |
FXNW_ONLY_NODE_TYPE |
2 | NodeDirectSale |
L2 不开放 USDT 通道 |
MIN_NODE_TYPE / MAX_NODE_TYPE |
2 / 3 | NodeDirectSale |
直购只卖 L2 和 L3 |
PERIOD |
30 天 | NodeMaintenance |
维护周期 |
BPS_DENOMINATOR |
10000 | NodeDirectSale |
burnBps 的分母 |
不在这个控制台里的东西
以下参数不是合约状态,本控制台没有、也不应该有它们的写入口。它们是结算账本的版本化参数,由结算侧的命令行工具写入,改动会进入快照哈希,链上留有指纹。
| 参数 | 生效时机 |
|---|---|
| 分母下限系数 k | 次日结算日起,不追溯 |
| 日产率 | 同上 |
| 解锁天数 | 同上 |
| L2 内盘合成价 | 立即,可指定生效时刻 |
本控制台唯一的写路径是钱包签名。它不写数据库,也不调用后端的写接口。
部署顺序
只讲第二阶段这九个合约。FastXNodeNFT、ReferralRegistry、NodeSale 已经在主网跑了三个月,不在部署范围内,它们是新合约要挂上去的既有事实层。
思路是:用部署钱包一把部完,角色和参数全部到这个控制台里配,最后再把最高权限交出去。 这样部署当天不需要每一步都走多签,但代价是有一段窗口期,那把 EOA 私钥掌握全系统。窗口多长由你决定,最后一步必须有截止日期。
部署前必须定死的
这些没有 setter,改就得重新部署:
| 项 | 定在哪 | 说明 |
|---|---|---|
usdt / nodeNFT / referralRegistry / fxnw 地址 |
各合约构造参数,immutable |
部署顺序对了就自然对 |
| FXNW 的地址 | 同上 | 由项目方提供,见下一节 |
treasury 和 vault 有 setter,可以事后改,但改到正式地址之前不要开卖,否则钱已经进了部署钱包。
顺序
- 拿齐前置:项目方给出 FXNW 地址;定好
treasury与vault的正式地址;准备好铸造热钱包与结算热钱包的地址(可以先留空)。 - 部署 Phase B:
NodeMaintenance、MiningSettlement。 - 部署 Phase C:
NodeMintGateway、NodeCompose、NodeDirectSale、FXNWClaim。 - 部署
AICClaim与NodeComposeVoucher。两者都要setSigner指到后端对应的签名 key,都要把PAUSER_ROLE授给运维 EOA。 - 授合约之间的角色,用
GrantMiningPhaseCRoles脚本:NFT 的MINTER_ROLE给网关、合成、直购;COMPOSER_ROLE给合成;MAINTENANCE_ROLE给维护费合约;Registry 的ATTRIBUTION_RECORDER_ROLE给前三个。这些地址要合约部出来才知道,所以只能这一步做。 - 把网关的
GATEWAY_OPERATOR_ROLE授给NodeComposeVoucher。 网关的 admin 在 Phase C 脚本里已移交多签,所以这一笔由多签执行。漏了它,凭证合约读什么都正常,每一笔赎回都 revert。 - 在控制台配业务角色:
GATEWAY_OPERATOR_ROLE给铸造热钱包,只给这一个;PUBLISHER_ROLE给结算与提现热钱包。铸造钱包在 NFT 与 Registry 上不应有任何角色。 - 在控制台配参数:直购的两种币价与上限、
burnBps、维护费率、每日铸造上限、合成开关。 - 开卖前把
treasury与vault改到正式地址,在合约总览里读回确认。 - 最后交权:每个合约的
DEFAULT_ADMIN_ROLE从部署钱包迁到多签,在授权与撤销那一档做。先授多签、在界面上确认多签确实持有、再撤 EOA。顺序护栏会挡住反过来的操作,但挡不了「一直没做」。
窗口期的那把钥匙
第 2 步到第 9 步之间,部署钱包的私钥能铸 NFT、改价格、改收款地址、授撤任何角色。它在这段时间就是全系统最高价值的密钥,按这个等级保管。第 9 步不是「稳定之后再说」,给它一个日期。
关于 FXNW(不由本项目部署)
FXNW 由项目方部署,矿池打多少、什么时候打,都不影响本项目的部署与运行。合约只把它当一个 ERC20 地址收下。
矿池那个钱包没有任何合约引用它,它只是项目方存币的地方。真正要看的是 FXNWClaim 的余额够不够 outstandingAmount,这两个数在合约总览里都能读到。
本项目对那个代币有三条要求,送审的 FastXNetworkToken 三条都满足(ERC20 + ERC20Burnable,无 decimals() override,无转账钩子):
| 要求 | 为什么 | 送审版本 |
|---|---|---|
| 精度 18 | 直购价、提现金额、界面显示都按 18 位算 | 未 override,取 OpenZeppelin 默认 18 |
有公开的 burn(uint256) |
NodeDirectSale 收到 FXNW 后按 burnBps 销毁自己那一份,没有就每笔直购都失败 |
继承 ERC20Burnable |
| 转账不收手续费 | 直购先整额收进合约,再精确拆分销毁与进 vault;到账少于预期会算错 | 未 override _update / _transfer |
送审版本另外没有 mint、没有暂停、没有黑名单,构造完供应量固定,不存在管理员冻结本项目合约的路径。
总量与分配不由代币强制。 构造函数只接收一个 initialSupply 和一个 recipient,全额铸给它。7 亿矿池、3 亿金库那个拆分是项目方部署后自己转出去的,链上没有约束。因此不要假设读到的 totalSupply 一定是 10 亿。
拿到地址后,在合约总览的 FXNW 那一行核对 symbol 与 decimals,精度不是 18 会显著标出。
提现开放之前,FXNWClaim 不需要有钱;注资就是往合约地址转 FXNW,按期注即可。