Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
集成与开发阅读约 11 分钟

Polygon 与 Polymarket:链上读取预测市场数据

一套可复现的工作流程,用于读取 Polymarket 的 Polygon 合约、验证交易并测量 RPC 行为,无需依赖未经核实的仪表板。

TL;DR

Polymarket 是一个预测市场,其交易活动历史上在 Polygon 网络上结算,头寸由代币化的结果份额表示,结算通过乐观预言机处理。本指南解释了该架构背后的思维模型,然后逐步介绍一个可运行的程序,使用 JSON-RPC 从 Polygon 读取 Polymarket 相关合约和事件。它将已记录的行为与建议以及你必须针对自己的 RPC 端点自行运行的测量区分开来。目标是提供一种可重复的方式来验证仪表板所声称的内容,而不是一份可复制的端点列表。

范围与本指南涵盖的内容

本文讨论 Polygon 与 Polymarket 之间的技术关系:预测市场头寸如何在链上表示,如何通过标准 JSON-RPC 方法查询它们,以及如何衡量你的 Polygon 访问层是否足以应对工作负载。本文面向构建仪表板、分析管道或交易工具的开发者,这些工具需要读取 Polymarket 活动,而不是通过 Polymarket UI 下单交易。

全文适用两个假设。首先,你拥有一个自己控制或信任的 Polygon JSON-RPC 端点,以 RPC_URL 形式提供;本指南从不硬编码公共端点。其次,你理解基本的以太坊 JSON-RPC 概念,如区块、日志和 eth_call。如果你需要复习端点选择,RPC 端点指南涵盖了基础知识,多链 RPC 端点指南解释了如何跨网络构建访问结构。

  • 已记录的行为:Polymarket 已在 Polygon PoS 上运行,通过 Safe 实现自托管,并通过 UMA 的乐观预言机进行结算。
  • 建议:将任何单一仪表板数字视为假设,直到你从原始日志中复现它。
  • 测量:延迟、日志完整性和重组行为必须针对你自己的端点进行测试。

Polymarket 如何映射到 Polygon

预测市场需要其结算层提供三样东西:持有抵押品的方式、表示结果份额的方式以及解决市场的方式。在 Polygon 上,抵押品通常是稳定币(如 USDC),结果份额是类似 ERC-20 的代币或在市场合约中跟踪的头寸,结算由预言机驱动,预言机发布答案,市场合约在争议窗口后接受该答案。

Polygon 将 Polymarket 的公开架构描述为结合了链上可验证性、通过 Safe 智能账户实现自托管以及通过 UMA 的乐观预言机实现去中心化争议解决。这意味着对集成者有用的链上表面不是一个合约,而是一组合约:市场工厂、各个市场合约、条件代币合约以及持有用户资金的 Safe 账户。在编写任何代码之前,Polygon 网络页面是确认链标识符和当前网络参数的地方。

  • 抵押品:由市场或 Safe 合约持有的稳定币余额。
  • 头寸:代币化的结果份额,其余额在交易时变化。
  • 结算:预言机报告的结果在争议期后被市场合约接受。
  • 账户:许多用户使用基于 Safe 的智能账户,而非普通的外部拥有账户。

读取预测市场状态的思维模型

将每个 Polymarket 市场视为一个小型状态机。它从交易状态开始,当提交预言机答案时进入提议解决状态,最终结算。每次转换都会发出事件,这些事件是最便宜的可靠数据源,因为它们被索引并且可以按地址和主题过滤。

实际后果是,你应该围绕日志构建管道,而不是围绕对每个市场重复进行 eth_call 轮询。日志让你按顺序重建交易、拆分、合并和赎回。调用更适合时间点读取,例如当前余额或市场的解决状态。在没有明确边界的情况下混合两者是预测市场仪表板中重复计算的最常见来源。

先决条件和环境设置

JavaScript 示例需要 Node.js 18 或更高版本,原始 RPC 检查需要 curl 和 shell。导出你的端点和要检查的区块范围。不要提交真实密钥;示例仅使用占位符。

将 RPC_URL 设置为来自提供商的 Polygon 端点。如果你仍在共享访问和专用访问之间做决定,专用节点页面解释了私有节点何时值得付出成本,RPC 定价展示了请求量如何映射到计划。

export RPC_URL="https://your-polygon-endpoint.example"
export FROM_BLOCK=60000000
export TO_BLOCK=60001000
node --version

使用 curl 验证链标识和区块范围

在查询任何合约之前,确认你所在的链是你认为的链。eth_chainId 返回链标识符,eth_blockNumber 告诉你端点已同步到多远。这里的任何不匹配都会使所有下游结果无效。

运行以下命令并记录输出。预期的验证结果是链 ID 与 Polygon 的文档值匹配,并且区块号在相隔几秒的两次调用之间递增。如果区块号是静态的,则你的端点已过时或缓存了。

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"eth_blockNumber","params":[]}'

sleep 5

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":3,"method":"eth_blockNumber","params":[]}'

在 JavaScript 中获取 Polymarket 相关日志

下一步是在有界区块范围内拉取已知合约地址的日志。你必须从信任的来源(例如市场页面上列出的合约或经过验证的区块浏览器标签)自行提供地址。下面的脚本获取日志、打印计数,并在端点返回错误时以非零状态退出,这使其可用于 CI 检查。

起初保持范围较小。许多提供商限制 eth_getLogs 结果,静默截断看起来与安静的市场完全相同。在信任返回的计数之前,将其与第二个提供商或区块浏览器进行比较。

const RPC_URL = process.env.RPC_URL;
const ADDRESS = process.env.MARKET_ADDRESS;
const FROM = process.env.FROM_BLOCK;
const TO = process.env.TO_BLOCK;

async function rpc(method, params) {
  const res = await fetch(RPC_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params })
  });
  const json = await res.json();
  if (json.error) throw new Error(JSON.stringify(json.error));
  return json.result;
}

const logs = await rpc('eth_getLogs', [{
  address: ADDRESS,
  fromBlock: '0x' + Number(FROM).toString(16),
  toBlock: '0x' + Number(TO).toString(16)
}]);

console.log('log count:', logs.length);
console.log('first block:', logs[0]?.blockNumber ?? 'none');

使用 eth_call 读取市场的解决状态

时间点读取使用针对特定区块的 eth_call。你需要所调用函数的合约 ABI 片段。下面的示例假设一个返回布尔型 resolved 标志的函数;请替换为你正在检查的合约中的真实选择器和 ABI。手动编码调用容易出错,因此在生产环境中使用 viem 或 ethers 等库。

预期的验证结果是解码后的值与市场页面在同一区块显示的值匹配。如果不匹配,请显式固定区块号并重试;状态可能在你的读取和 UI 的读取之间发生变化。

import { createPublicClient, http, parseAbi } from 'viem';

const client = createPublicClient({
  transport: http(process.env.RPC_URL)
});

const abi = parseAbi([
  'function resolved() view returns (bool)'
]);

const blockNumber = await client.getBlockNumber();
const resolved = await client.readContract({
  address: process.env.MARKET_ADDRESS,
  abi,
  functionName: 'resolved',
  blockNumber
});

console.log({ blockNumber, resolved });

针对此工作负载测量端点行为

预测市场分析是日志密集且突发性的。在重大事件期间,许多客户端同时请求相同的近期区块范围。你应该在自己的端点上测量三件事:固定范围的日志查询延迟、重复相同查询下的成功率,以及两个端点之间的结果是否一致。

每个测量至少运行 30 次,并将结果记录在下表中。不要填写本文中的数字;单元格故意留空,因为只有你的环境才能产生它们。一个有用的比较是共享端点与专用节点,区块链节点托管指南从操作角度描述了这一点。

  • | 指标 | 端点 A | 端点 B | 备注 |
  • | --- | --- | --- | --- |
  • | 1,000 个区块的 eth_getLogs 延迟中位数 | | | 相同地址和范围 |
  • | p95 延迟 | | | 注意提供商限制 |
  • | 30 次运行的成功率 | | | 统计 JSON-RPC 错误 |
  • | 日志计数一致性 | | | 必须完全匹配 |
  • | 60 秒内 eth_blockNumber 漂移 | | | 应为非零 |

排查常见集成故障

大多数故障属于几类。范围过大错误意味着提供商限制了 eth_getLogs;拆分范围并分页。繁忙市场上的空结果通常意味着地址错误、主题过滤器错误或范围在市场存在之前。提供商之间的计数不一致通常意味着一个端点落后或应用了结果上限而没有告知你。

如果 eth_call 回滚,请检查你读取的区块中合约是否存在,以及你的 ABI 是否与部署的字节码匹配。如果 Safe 持有的头寸似乎缺失,请记住所有者是 Safe,而不是用户的签名密钥;查询 Safe 地址,而不是 EOA。有关更广泛的端点可靠性模式,可靠性与一致性类别是合适的参考。

  • 范围错误:以固定大小的窗口分页,并记录每个窗口的计数。
  • 空日志:验证地址校验和、topic0 和部署区块。
  • 回滚:固定区块号并根据已验证的源代码确认 ABI。
  • 余额缺失:查询 Safe 合约,而不是签名者。

局限性、权衡以及不应假设的内容

链上数据告诉你什么已结算,而不是意图是什么。链下订单匹配、UI 显示和某些元数据可能永远不会出现在日志中,因此纯链上重建可能会低估活动。预言机解决引入了一个争议窗口,在此期间市场的表观结果可能会改变;在窗口关闭之前,将提议的结果视为临时的。

还有一个治理和基础设施维度。公开讨论提出了 Polymarket 运营自己的链或随时间改变结算基础设施的可能性。因此,任何集成都应从配置中读取合约地址和链 ID,而不是硬编码关于 Polymarket 运行位置的假设。本文描述基于 Polygon 的模型,因为它是已记录且可观察的模型,而不是因为它保证保持不变。

生产管道的后续步骤

从临时查询转向索引管道:一个在有界窗口中遍历历史日志的回填作业,一个跟随新块的实时尾部,以及一个将你推导的总量与第二个来源进行比较的对账作业。在解码之前存储原始日志,以便在 ABI 或解释变化时重新推导指标。

对于端点选择,将决策与管道设计分开。API 服务概述解释了托管访问的结构,如果你想要直接推荐而不是方法论,RPC Assistant 的简短指南如最佳以太坊 RPC API是合适的查阅位置。最后,将你自己测量的延迟和一致性数字与管道一起记录,以便未来的变更可以根据基线而不是记忆来评估。

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始