内部文档:公式一致性审计报告
状态: 持续维护 | 更新: 2026-08-05 范围: 部署合约 (BSC 主网) ↔ Rust 模拟器 (
The-Game-Economy-Simulation) ↔ 前端 (packages/client) 原则: 合约已重新部署(2026-08-05),采用定点速率方案。
0. 2026-08-05 合约修复(已部署主网)
修复 _calcCollect 与 _dailyEnergy 的整数 sqrt 平台期问题,最终采用定点 ×1e6 + 线性保底:
| 函数 | 修复前 | 修复后(已部署) |
|---|---|---|
_calcCollect | 3 + 10×⌊√(L-1)⌋(Lv2=Lv3=Lv4=13/s 平台期) | rate_fp = 3e6 + 10×⌊√((L-1)×1e12)⌋ + 2_400_000×(L-1),结算 ×rate_fp/1e6,view 返回定点 |
_dailyEnergy | 86400×(3×1e6+10×⌊√((L-1)×1e6)⌋)/1e6(bonus 被 ÷1000 缩小) | 86400 × _calcCollect(L,0) / 1e6(与采集同源) |
要点:
- 速率 = (3 + 10√(L-1) + 2.4×(L-1)) /s,定点 ×1e6 存储;1-1000 级每级严格递增,0 平台期
- 线性项 2.4/s/级保证后期升级仍有明显增量(Lv999 每级 +2.56/s)
- Lv1000 速率 ≈ 2717/s;回本天数 = 锚定天数(30→60 天封顶,成本与产出同源相消)
- 新增 view:
getPendingEnergy(待收取能量,与结算一致)、getUpgradePreview(当前/下一级值)、getShieldDefense、getSpeed、getRadarRange - 前端已移除全部本地公式(
calcCollectRate等),数值一律读链上 view - 前端
collectEnergytoast 读EnergyCollected事件实际值 - 合约测试 32 套件全过(含 fork 主网迁移验证);模拟器 18/18;agent ABI 已同步
1. 已知公式偏差(合约内部自洽性问题)
1.1 _calcCollect 整数 sqrt vs _dailyEnergy 定点 sqrt ✅ 已修复
_calcCollect 整数 sqrt vs _dailyEnergy 定点 sqrt2026-08-04 修复,见第 0 节。以下为修复前的历史记录。
现象: 采集速率有平台期,相邻等级速率可能不变(Lv2=Lv3=Lv4=13/s)。
| 函数 | 用途 | 公式 | sqrt 方式 |
|---|---|---|---|
_calcCollect (Storage.sol:550) | 实际采集 (_collectEnergy) | 3 + 10 × _sqrt(L-1) | 整数 sqrt(向下取整) |
_dailyEnergy (Storage.sol:454) | 升级能量成本 (_anchorEnergyCost) | 86400×(3×1e6 + 10×_sqrtUint((L-1)×1e6))/1e6 | 定点 sqrt(×1e6) |
影响:
- 实际采集产出按整数 sqrt 结算,玩家 Lv3 实得 13/s(非设计意图的 17.14/s)
- 升级成本按定点 sqrt 估算每日能量(Lv3≈3.01/s),与产出 13/s 严重脱节(差 ~4.3 倍)
- 跳变点: Lv2→13, Lv5→23, Lv10→33, Lv17→43, Lv26→53, Lv37→63, Lv50→73, Lv65→83, Lv82→93
- 100 级速率表见下
处置: 合约不可改,模拟器已 bug 兼容(math_engine.rs calc_collect 用 isqrt)。前端 calcCollectRate 已改为整数 sqrt(2026-08-04 修复)。
1.2 1-100 级实际采集速率表
Lv1: 3/s Lv2-4: 13/s Lv5-9: 23/s Lv10-16: 33/s
Lv17-25: 43/s Lv26-36: 53/s Lv37-49: 63/s Lv50-64: 73/s
Lv65-81: 83/s Lv82-100: 93/s
2. 公式级偏差(模拟器 vs 合约)
2.1 护盾再生成本 ❌ 严重不符
| 侧 | 公式 |
|---|---|
合约 regenShield (Battle.sol:241-249) | cost = regenRate × SHIELD_REGEN_ENERGY_RATIO(1) = (50 + lv²) × 1 |
模拟器 calc_shield_regen_cost (math_engine.rs:659) | SHIELD_REGEN_COST_BASE(100_000) + SHIELD_REGEN_COST_PER_LV(30_000) × lv |
合约成本 = 50 + lv²;模拟器 = 100000 + 30000×lv。量级差 ~2000 倍,且曲线形态不同(二次 vs 线性)。
模拟器 _daily_step 护盾再生(engine.rs:332-338)用 regen×12 每 tick,成本按 regen × SHIELD_REGEN_RATIO()——需确认 SHIELD_REGEN_RATIO 参数值是否=1。待修复。
2.2 攻击 token 再生间隔 ✅ 实际一致
合约 _regenTokens (Battle.sol:65-84): intervalMs = 300 - lv×10(clamp≥100)→ /100 秒 → clamp 到 TOKEN_MIN_INTERVAL(1)。
模拟器: calc_token_regen_interval 返回 clamp≥100 的 ms,engine.rs:316 /100 得秒。
逐等级验证 Lv0-30 完全一致(Lv≤10: 2-3s,Lv≥11: 1s)。无差异。
2.3 雷达系统耐久 ❌ 模拟器死代码
- 合约
_calcMaxSystemDur(Storage.sol:559-564): 只含 WEAPON/SHIELD/ENGINE,RADAR 返回 0,无雷达耐久存储 - 模拟器定义了
RADAR_DUR_BASE/RADAR_DUR_PER_LV/RADAR_REPAIR_COST参数与calc_max_system_dur的 RADAR 分支,但无任何调用方(死代码) - 模拟器
calc_repair_cost、calc_shield_regen_cost(SHIELD_REGEN_COST_BASE=100000 + 30000×lv)同样无调用方——是旧设计残留
处置: 可安全清理;不影响任何运行路径。
2.4 护盾再生 tick ⚠️ 每日 12 次近似
- 合约
regenShield(Battle.sol:241-249): 单次调用恢复regenRate(50+lv²)HP、消耗regenRate × SHIELD_REGEN_ENERGY_RATIO(1)能量 - 模拟器 engine.rs:332-338: 每个
_daily_step恢复regen×12HP、消耗regen×12 × SHIELD_REGEN_RATIO(1)——即「每天自动 12 次再生」的近似
恢复量与成本同步 ×12,内部自洽;与合约差异仅在于「玩家手动调用次数」的假设(模拟器假设每天自动触发 12 次)。可接受,非 bug。
3. 已确认一致(无需改动)
| 公式 | 合约位置 | 模拟器 | 前端 |
|---|---|---|---|
_anchorDaysBps(含 M-01 snap N=99→300000) | Storage.sol:439 | _anchor_days_bps ✓ | — |
_dailySes (L 非 L-1) | Storage.sol:463 | calc_upgrade_cost ✓ | — |
_dailyEnergy 定点 | Storage.sol:454 | daily_energy_at_level_impl ✓ | — |
_anchorEnergyCost/_anchorSesCost | Storage.sol:468/476 | ✓ | — |
_calcAttack 900+10L² | Storage.sol:544 | calc_attack ✓ | calcAttackPower ✓ |
_calcShieldDefense 540+6L² | Storage.sol:545 | calc_defense ✓ | calcShieldDefense ✓ |
_calcShieldHP 3600+15L² | Storage.sol:543 | calc_shield_hp ✓ | calcMaxShieldHP ✓ |
_calcShieldRegen 50+L² | Storage.sol:546 | calc_shield_regen ✓ | — |
_calcRadar 1000+150L+5L² | Storage.sol:548 | calc_radar ✓ | calcRadarRange ✓ |
_calcSpeed 10+5(L-1) | Storage.sol:539 | calc_speed ✓ | calcSpeed ✓ |
_calcCollect 整数 sqrt | Storage.sol:550 | calc_collect ✓ | calcCollectRate ✓ (已修) |
_calcMaxDurability | Storage.sol:555 | calc_max_durability ✓ | — |
_calcMaxSystemDur (W/S/E) | Storage.sol:559 | ✓ | — |
_plunderRatio 500+Lv×50 | Battle.sol:61 | ✓ | — |
跳跃成本 _sqrt(jc) | Movement.sol:28-31 | calc_jump_energy/ses_cost ✓ | — |
token 上限 3+lv/10 cap 10 | Battle.sol:73-74 | calc_max_tokens ✓ | — |
_upgradeEnergyMultiplier 1/4/4/8/16 | Storage.sol:422 | _anchor_mult ✓ | — |
| 重建成本 500K×梯度 | Admin.sol:178-198 | try_rebuild ✓ | — |
4. 参数一致性(params.json 默认值 vs 合约常量)
已完成收敛(2026-08 审计): upkeep_per_level=2000、jump_energy_base/per_sqrt=200_000、jump_ses_base=10e18、jump_ses_max=1000e18、max_alliance_members=100、scan_range=1000。
5. 待办清单
- 清理模拟器死代码:
calc_shield_regen_cost+SHIELD_REGEN_COST_BASE/PER_LV参数、calc_repair_cost、雷达耐久参数/分支(2026-08-04 已清理,17/17 测试通过) - 修复合约
_calcCollect/_dailyEnergy定点 sqrt 平台期(2026-08-04,31 套件测试全过) - 前端
calcCollectRate、模拟器公式同步修复(2026-08-04) - BSC 测试网部署验证新合约(全新部署 + 状态迁移脚本)
- 主网升级:迁移唯一玩家「起源」状态到新合约,前端切新地址
- 前端展示跳变提示(可选:速率卡标注「LvX 跳变」——修复后低等级已无平台,此需求降级)