xtruth

在智能合约里接入 OOv3

标准模式:你的合约持有资金,市场到期时调 assertTruth(),通过回调拿到 结果。这与主流预测市场平台的做法一致。

先在沙盒里跑通:把你的集成合约部到 X Layer 测试网(chainId 1952), 指向同一份 OOv3 地址(合约地址),用 app-dev.xtruth.xyz 做断言/争议/结算 的 UI 调试。准备好了再切到 app.xtruth.xyz。 详见 环境

最小预测市场合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { OptimisticOracleV3Interface } from
  "./interfaces/OptimisticOracleV3Interface.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract YesNoMarket {
    OptimisticOracleV3Interface public immutable oo;
    IERC20 public immutable bondCurrency;
    bytes32 public constant identifier = "ASSERT_TRUTH";

    struct Market {
        bool resolved;
        bool outcome;        // true = YES
        bytes32 assertionId;
    }
    mapping(bytes32 => Market) public markets;

    constructor(address oov3, address currency) {
        oo = OptimisticOracleV3Interface(oov3);
        bondCurrency = IERC20(currency);
    }

    /// 任何人可以通过质押 + 断言来解析市场结果。
    function resolve(bytes32 marketId, string calldata claim, uint64 liveness) external {
        require(!markets[marketId].resolved, "already resolved");

        uint256 bond = oo.getMinimumBond(address(bondCurrency));
        bondCurrency.transferFrom(msg.sender, address(this), bond);
        bondCurrency.approve(address(oo), bond);

        bytes32 assertionId = oo.assertTruth(
            bytes(claim),
            msg.sender,            // 断言者
            address(this),         // 回调目标
            address(0),            // 自定义升级管理器
            liveness,
            bondCurrency,
            bond,
            identifier,
            bytes32(0)
        );
        markets[marketId].assertionId = assertionId;
    }

    /// OOv3 在结算时回调(无论真假)。
    function assertionResolvedCallback(
        bytes32 assertionId,
        bool assertedTruthfully
    ) external {
        require(msg.sender == address(oo), "only OO");
        // 找到对应市场,记录结果,给胜方发钱。(查表细节略。)
    }

    /// 可选:被争议时的钩子(升级到 DVM)。
    function assertionDisputedCallback(bytes32 assertionId) external {
        require(msg.sender == address(oo), "only OO");
        // 在 UI 上显示"争议中";冻结待发的支付。
    }
}

关键参数选择

保证金

getMinimumBond(currency) 返回该代币的最小保证金;你也可以设更高。 保证金越高,争议成本越高,适合高价值市场。

挑战期 liveness

权衡:

OOv3 默认 2 小时。Polymarket 根据市场大小用 2 小时到几天不等。

Identifier

OOv3 最常用 ASSERT_TRUTH,意为"声明 claim 文本为真,无人争议则判真"。 也可以用 YES_OR_NO_QUERYNUMERICALMULTIPLE_CHOICE_QUERY, 但只在你的升级管理器对其做特殊解释时才有意义。

自定义升级管理器

默认走 address(0) 即原生 DVM 流程。如果想自定义(白名单争议者、 强制多签后才能升级等),实现 EscalationManagerInterface 并传它的地址。

回调注意事项

从合约自己授权

合约(而非用户)押保证金时,通常做法是合约预先存入 bond 币, 然后在 resolve() 内 approve OOv3。如果不想每次烧 gas approve, 部署时一次性 approve type(uint256).max

ABI

OptimisticOracleV3 的接口和读写 ABI 打包在 xtruth-app/src/lib/contracts/oov3-abi.ts。 我们用到的核心函数:

function assertTruth(
    bytes memory claim,
    address asserter,
    address callbackRecipient,
    address escalationManager,
    uint64 liveness,
    IERC20 currency,
    uint256 bond,
    bytes32 identifier,
    bytes32 domainId
) external returns (bytes32 assertionId);