fix[polymarket-monitor]: resolve markets via CLOB condition lookup#4945
fix[polymarket-monitor]: resolve markets via CLOB condition lookup#4945
Conversation
Signed-off-by: Pablo Maldonado <pablo@umaproject.org>
| clobTokenIds: JSON.parse(market.clobTokenIds), | ||
| }; | ||
| }); | ||
| return [processMarket(await fetchGammaMarket(clobMarket))]; |
There was a problem hiding this comment.
This changes the function from returning every Gamma match for question_id, neg_risk_request_id, or game_id to returning exactly one market from the first CLOB hit. For sports proposals, can that drop sibling markets that share the same game_id and skip discrepancy checks that the previous path covered?
There was a problem hiding this comment.
Good catch. I think this sports path probably is not exercised in practice anymore because I don’t think this identifier/requester combination is still used, but you’re right that the change regressed the old behavior for sports. I’ve fixed it so we still do the canonical CLOB/neg-risk discovery, then expand sports proposals back out to all sibling markets from the Gamma event via public REST.
| params.apiEndpoint = "https://clob.polymarket.com"; | ||
| params.graphqlEndpoint = "https://gamma-api.polymarket.com/query"; | ||
|
|
||
| const questionId = "0x6e0a8c466f66bc6f7d3f113d3dcf019035adf909fd6efcca0368c3bec245914b"; |
There was a problem hiding this comment.
This test only covers the standard requester-derived condition id. The PR description says the real failure was the neg-risk fallback via questionIds() and nrAdapter(). Can we add a case where the standard CLOB lookup misses, the operator resolves the canonical question id, and the fallback condition id succeeds?
| }; | ||
| }; | ||
|
|
||
| const gammaApiBaseUrl = params.graphqlEndpoint.replace(/\/query\/?$/, ""); |
There was a problem hiding this comment.
This lookup path is now entirely public REST. Should initMonitoringParams() still hard-require POLYMARKET_API_KEY? Otherwise the monitor can still fail to start without a secret this change no longer uses.
Signed-off-by: Pablo Maldonado <pablo@umaproject.org>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d566d1d61
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ].filter((url): url is string => Boolean(url)); | ||
|
|
||
| for (const url of candidateUrls) { | ||
| const { data } = await params.httpClient.get<PolymarketMarketResponse | PolymarketMarketResponse[]>(url); |
There was a problem hiding this comment.
Continue Gamma fallback URLs after a 404
The fetchGammaMarket loop builds slug, market_id, and id URLs as fallbacks, but an HTTP 404 from the first candidate throws immediately and prevents trying the remaining candidates. In practice, if market_slug is stale/missing while market_id is still valid, this path now reports the market as not found even though a later URL would succeed.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch, fixed in 3c5e56ad. We now continue through the Gamma fallback URLs on 404, so a stale/missing slug still falls back to market_id/id. I also added a regression test that exercises the slug -> market_id path.
| }; | ||
|
|
||
| const findClobMarket = async (): Promise<ClobMarketResponse | null> => { | ||
| const conditionIds = [...getStandardConditionIds(questionID), ...(await getNegRiskConditionIds())]; |
There was a problem hiding this comment.
Make neg-risk operator lookup a true fallback
This line eagerly awaits getNegRiskConditionIds() before any CLOB lookup, so every proposal now performs on-chain neg-risk resolution calls even when the standard requester-based condition ID works. That is a regression from the intended “only if standard miss” flow and can materially slow monitoring or increase RPC pressure/rate-limit risk under load.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch, fixed in 3c5e56ad. Neg-risk resolution is now a true fallback again: we first try the standard requester-derived condition ids, and only call into the neg-risk operator path if those miss. I also tightened the happy-path test to assert we do not touch the provider when the standard lookup succeeds.
Summary
This changes
monitor-polymarketmarket resolution to stop relying on Gamma GraphQL identifier lookups.New flow:
condition_idfromproposal.requester + questionIDkeccak256(ancillaryData)as a possible neg-risk request id and resolve the canonical question id on-chain throughNegRiskOperator.questionIds(...)condition_idand fetch the market from CLOB bycondition_idProblem
On April 8, 2026, the notifier failed to verify a valid neg-risk Polymarket proposal because it used
keccak256(ancillaryData)as a direct Gamma GraphQL lookup key.That is brittle for neg-risk markets because the ancillary hash is the neg-risk request id, not always the canonical market
questionID. As a result, the bot could fail on the metadata lookup path even when the market existed and was otherwise resolvable.Concrete failing example:
1272207)questionID:0x303df379b982e189dc6aea356cad409cd18b8bc634a95e318b5e7ef025ab44000x6e0a8c466f66bc6f7d3f113d3dcf019035adf909fd6efcca0368c3bec245914bWhy this fix
This makes market discovery follow the on-chain/CLOB identity path instead of depending on:
market_idThe notifier still returns the same market metadata shape after the lookup succeeds, because it uses the public Gamma REST payload only after CLOB has identified the market.
Validation
yarn workspace @uma/monitor-v2 buildyarn workspace @uma/monitor-v2 test test/PolymarketMonitor.ts --grep 'resolves markets through CLOB condition lookup and Gamma slug lookup'https://polygon-mainnet.g.alchemy.com/v2/DnSj5ge0vStbqvOYzEhSV852743972026-04-08T17:20:31Z0x2F5e3684cb1F318ec51b00Edba38d79Ac2c0aA9d0xad2a68d579ad978d0dea48a359f3058442cd0eda5a04900109cc40160d5672e0GET https://clob.polymarket.com/markets/0x7a73edc351f3a81f146f24cb3fe8d69448b22b9225e9c4799272a8ceb1fe5801-> miss on the standard requestercondition_idGET https://clob.polymarket.com/markets/0xf77c27919433746aa6ff6759e36e8455458359f41a1f0dc75e6993736120091e-> hit on the neg-risk-resolvedcondition_idGET https://gamma-api.polymarket.com/markets/slug/mex-que-jua-2026-02-22-que-> returns the expected market metadataPOST https://gamma-api.polymarket.com/queryquestionID:0x303df379b982e189dc6aea356cad409cd18b8bc634a95e318b5e7ef025ab4400