跳到主要内容

算法

HyperPredictV1Pair 的角色

HyperPredictV1Pair 是一个链上交易对,与单个基础资产和交易间隔(intervalSeconds)绑定。每个交易对负责:

  • 让操作员(一个自动化机器人)从 Pyth 预言机中拉取价格并按顺序推进回合(epoch
  • 接受投注者的赌注和头寸(牛市/熊市)并将其存储在 ledgeruserRounds 映射中
  • 每当一个回合成功结束时,计算奖励基数(rewardBaseCalAmount)和要分配的金额(rewardAmount
  • 在无效回合或预言机中断期间保护资金,并在必要时允许退款

以下各节按顺序组织了回合生命周期、Pyth 集成、安全机制和奖励算法。

回合生命周期

每个回合有三个阶段,开始 → 锁定 → 结束,每个阶段都由 intervalSeconds 分隔。投注窗口从 startTimestamplockTimestamp,价格观察到 closeTimestampexecuteRound 将系统推进到下一步。

正常回合时间线

  • 调用 genesisStartRoundgenesisLockRound 各一次以引导第一个回合。
  • 创世之后,executeRound 在一个事务中为第 n 回合处理三个操作:
    1. 使用最新的预言机价格锁定第 n-1 回合。
    2. 结束第 n-2 回合并确定其最终价格。
    3. 为新的投注开启第 n 回合。
  • 为允许即使在连续调用延迟时也能安全暂停,工厂强制执行全局 bufferSeconds。任何未在 bufferSeconds 内完成的阶段都将被拒绝。

Pyth 预言机集成和回退

_getPriceFromOracle 依赖于 Pyth 的 getPriceNoOlderThan,因此只接受在 bufferSeconds 内发布的价格。安全性通过以下方式确保:

  • 将发布时间(publishTime)存储为 oracleLatestRoundId,防止操作员意外使用过时数据
  • 将 Pyth 的 expo 规范化为 PYTH_PRICE_DECIMALS (=8) 并为负值添加溢出检查
  • 每当无法获取价格或更新延迟超过 bufferSeconds 时,将 oracleCalled 保持为 false,这将触发稍后描述的退款路径

预言机回合丢失

当价格检索失败时,该回合被标记为“丢失”。因为它永远不满足 claimable 条件,投注者可以通过 refundable 路径全额取回他们的赌注。操作员可以通过调用 pause/unpause 或重播创世步骤来安全地恢复。

投注接收和状态管理

  • betBullbetBearwhenNotPausednonReentrant 保护,notContract 修饰符仅限 EOA 访问。
  • 对于每个回合,赌注被添加到 round.totalAmount 和特定方向的桶(bullAmount/bearAmount)中;禁止在同一回合内混合头寸。
  • 投注必须大于或等于 factory.minBetAmount() 以阻止粉尘垃圾邮件。
  • ledger[epoch][user] 存储投注 amount 及其 claimed 状态,两者都可以通过 getUserRounds 进行分页。
  • 如果一个回合以 oracleCalled == false 结束,用户可以在 block.timestamp > closeTimestamp + bufferSeconds 后请求退款。

奖励计算算法

当操作员调用 executeRound 时,第 n-2 回合的奖励被最终确定。合约使用以下方程式:

treasuryAmt = total * treasuryFee / 10000
rewardAmount = total - treasuryAmt
rewardBaseCalAmount = closePrice > lockPrice ? bullAmount : bearAmount
  • treasuryFeetreasuryFeeWithReferralreferralFee 在工厂级别配置(参见 hyperpredict-contract-v1/config/HyperPredictV1Factory.ts)。在 BSC 上,这些值分别为 3%1%1%
  • closePrice == lockPrice(平局)时,rewardAmount 变为 0,所有人都会收到退款。
  • 获胜玩家的基础赔付是 userAmount / rewardBaseCalAmount * rewardAmount。即使投注者后来有资格获得推荐回扣,此方程式也始终使用 treasuryFee(在 BSC 上为 3%),以保持链上数学的确定性。
  • 当一个回合无效时,_calculateRewards 会提前退出,并且彩池是可退款的。

推荐分配

推荐处理被推迟到领取时,并且仅当投注者有注册的推荐人时才在 _applyReferralBonus 内部运行:

  • referralFee (1%) 定义了资助推荐人的资金池。用户的份额是 referrerBonus = total * referralFee / 10000 * userBet / rewardBaseCalAmount,它从获胜者的赔付中减去并转移给推荐人。
  • 为了抵消该减法并使国库在存在推荐时有效地只收取 treasuryFeeWithReferral(1%),获胜者还会收到回扣。回扣池是 (treasuryFee - treasuryFeeWithReferral)(在 BSC 上为 2%),获胜者的部分是 winnerBonus = total * (treasuryFee - treasuryFeeWithReferral) / 10000 * userBet / rewardBaseCalAmount。此金额在执行领取时从累积的国库余额中扣除。
  • 支付给投注者的最终奖励是 baseReward + winnerBonus - referrerBonus。当没有推荐人时,_applyReferralBonus 会提前退出,投注者只收到 baseReward,因此国库保留全部 3%。

这种延迟计算确保有推荐的投注者最终会使用更便宜的费用计划(1% 国库费 + 1% 推荐费),而没有推荐的投注者则保持 3% 的固定国库费。

领取时执行

当用户调用 claim 时,_claim 按顺序评估每个 epoch

  1. 如果 oracleCalled == true 且条目是 claimable,则计算获胜方的 baseReward
  2. 运行 _applyReferralBonus 以结算推荐分割并最终确定 winnerBonus 以及任何推荐人奖励。
  3. 如果在 refundable 成立的情况下 oracleCalled == false,则只需返回原始赌注。
  4. 对每个 addedReward 求和,以原生货币发送总额,如果累积了推荐奖金,则在单独的转账中发送这些奖金,同时发出 ReferralPaid

具体例子

A: 在牛市上投注 100 USDC
B: 在熊市上投注 100 USDC
C: 推荐人 (邀请了 A)
treasuryFee = 3%
treasuryFeeWithReferral = 1%
referralFee = 1%
回合结果: 牛市获胜
  • totalAmount = 200 USDC
  • treasuryAmount (初始) = 200 * 0.03 = 6 USDC
  • rewardAmount = 200 - 6 = 194 USDC
  • rewardBaseCalAmount = bullAmount = 100 USDC
  • A 的 baseReward = 100 / 100 * 194 = 194 USDC
  • 推荐池 referralPool = 200 * 0.01 = 2 USDC 所以 referrerBonus = 2 USDC
  • 国库回扣池 treasuryRefundPool = 200 * (0.03 - 0.01) = 4 USDC 所以 winnerBonus = 4 USDC
  • 获胜者收到 194 + 4 - 2 = 196 USDC
  • 推荐人收到 2 USDC
  • 国库保留 6 - 4 = 2 USDC,这与推荐投注的 1% 计划相符

如果投注者没有推荐人,_applyReferralBonus 将完全跳过回扣路径:A 将只领取 194 USDC 的 baseReward,国库将保留全部 3%(6 USDC)。B 仍然会输,因为他们的头寸在金钱之外完成,除非预言机失败,在这种情况下,双方都可以退还他们的赌注。

安全和故障保护

  • 角色分离: onlyOperator 驱动回合进程,而 onlyAdmin 处理国库操作(claimTreasuryrecoverToken)。
  • 可暂停 + 创世: 异常情况可以通过 pause 暂停,然后通过 genesisStartRound/genesisLockRound 清理重启,避免重复或未定义的回合。
  • ReentrancyGuard 和非合约门: 包括赔付路径在内的每个函数都是非重入的,并且只允许 EOA,从而阻止了多重调用合约。
  • 缓冲区强制: _safeLockRound_safeEndRound 拒绝 bufferSeconds 之外的操作,从而阻止了时间游戏和价格操纵。
  • 资金保护: claimable/refundable 条件在预言机停机期间防止双重领取,同时保证本金返还。
  • 预言机输入验证: getPriceNoOlderThan 会丢弃过时数据并清理负值或溢出情况。

这些机制共同确保 HyperPredictV1Pair 能够安全、自主地运行完全在链上的预测市场,并具有透明的赔付和推荐核算。