Skip to content

feat(rtds): chainlink twap price streams - #105

Open
jclmnop wants to merge 1 commit into
Polymarket:mainfrom
jclmnop:feat/rtds-twap
Open

feat(rtds): chainlink twap price streams#105
jclmnop wants to merge 1 commit into
Polymarket:mainfrom
jclmnop:feat/rtds-twap

Conversation

@jclmnop

@jclmnop jclmnop commented Aug 22, 2026

Copy link
Copy Markdown

Pretty self explanatory, adds support for the RTDS Chainlink TWAP Prices.

The 5m and 15m crypto markets recently started using this as their resolution source.

Pretty much just mirrored the existing chailink price stuff, with some minor refactoring (some constants for topics etc) along the way. Also added the explicit captures to RTDS streams (+ use<S> etc) like I did with clob ws streams so consumers can actually do stuff with them like merging, mapping, filtering etc (see this PR in the old SDK repo for more info on that).

I know this PR won't ever get merged because it seems you guys have stopped merging external PRs (maybe because there are too many LLM PRs these days? maybe because you're working on a new rust SDK that replaces this one again? idk), but opening it anyway so others can merge into their forks if they want.

Tested it out on some actual feeds and it works:

  2026-08-22T11:04:14.419094Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396653000, value: 76827.61626316469, window_s: 60 }, event.timestamp: 2026-08-22T11:04:13Z, staleness: 1.419083
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:15.282556Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396654000, value: 76827.31417347504, window_s: 60 }, event.timestamp: 2026-08-22T11:04:14Z, staleness: 1.282545
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:16.890732Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396655000, value: 76827.1043728313, window_s: 60 }, event.timestamp: 2026-08-22T11:04:15Z, staleness: 1.890726
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:17.669656Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396656000, value: 76826.96163536851, window_s: 60 }, event.timestamp: 2026-08-22T11:04:16Z, staleness: 1.669647
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:18.499283Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396657000, value: 76826.82782518922, window_s: 60 }, event.timestamp: 2026-08-22T11:04:17Z, staleness: 1.499271
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:19.555107Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396658000, value: 76826.69815014195, window_s: 60 }, event.timestamp: 2026-08-22T11:04:18Z, staleness: 1.555097
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:21.227707Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396659000, value: 76826.53042542443, window_s: 60 }, event.timestamp: 2026-08-22T11:04:19Z, staleness: 2.227701
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:22.003366Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396660000, value: 76826.50189643573, window_s: 60 }, event.timestamp: 2026-08-22T11:04:20Z, staleness: 2.003361
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:22.730005Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396661000, value: 76826.50189643573, window_s: 60 }, event.timestamp: 2026-08-22T11:04:21Z, staleness: 1.729996
    at src/bin/scratch.rs:59 on main

  2026-08-22T11:04:23.653433Z  INFO scratch: event: ChainlinkTwapPrice { symbol: "btc/usd", timestamp: 1787396662000, value: 76826.49423858756, window_s: 60 }, event.timestamp: 2026-08-22T11:04:22Z, staleness: 1.653427

Note

Low Risk
Additive RTDS client API and serialization tests; no auth, trading, or data-handling changes.

Overview
Adds RTDS support for Chainlink TWAP price feeds (crypto_prices_twap_{thirty,sixty}), matching the existing Chainlink spot stream.

subscribe_chainlink_twap_prices takes an optional symbol and a ChainlinkTwapWindow. Unsubscribe can target one window or all. Filters still serialize as escaped JSON strings for Chainlink topics.

Also adds precise + use<> / + use<S> captures on RTDS subscribe methods so returned streams can be composed. New types (ChainlinkTwapPrice, ChainlinkTwapWindow) are re-exported.

Reviewed by Cursor Bugbot for commit eee742f. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/rtds/client.rs

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit eee742f. Configure here.

Comment thread src/rtds/client.rs
pub fn unsubscribe_chainlink_twap_prices(
&self,
twap_window: impl Into<Option<ChainlinkTwapWindow>>,
) -> Result<()> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awkward unsubscribe None API

Low Severity

unsubscribe_chainlink_twap_prices takes impl Into&lt;Option&lt;ChainlinkTwapWindow&gt;&gt; while its docs say to pass None for all windows. Bare None does not infer here, unlike sibling helpers such as unsubscribe_comments(Option&lt;...&gt;), so the documented call shape is awkward to use.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit eee742f. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bare None does infer here. These would all be valid calls:

client.unsubscribe_chainlink_twap_prices(ChainlinkTwapWindow::SixtySeconds)?;
client.unsubscribe_chainlink_twap_prices(ChainlinkTwapWindow::ThirtySeconds)?;
client.unsubscribe_chainlink_twap_prices(None)?;

@yovanoc

yovanoc commented Aug 28, 2026

Copy link
Copy Markdown

Thanks for adding this — PMKit is consuming the 60-second Chainlink TWAP topic and this typed API is preferable to its temporary subscribe_raw adapter.

I validated this commit cherry-picked on top of #110: 167 library tests and all 45 WebSocket tests pass together. Two small blockers for our use:

  1. The TWAP fixture includes full_accuracy_value, but ChainlinkTwapPrice currently discards it. We use that exact string as durable boundary evidence alongside the display value; could the typed struct preserve it (including a round-trip assertion)?
  2. The repository's strict clippy command currently flags impl Into<Option<ChainlinkTwapWindow>> under clippy::impl_trait_in_params; a named generic parameter fixes it.

Happy to retain and consume this PR once the exact value is exposed.

@yovanoc

yovanoc commented Aug 29, 2026

Copy link
Copy Markdown

Follow-up: I combined #105 with #110 on fork branch integration/rtds-twap-market-stream, adding full_accuracy_value and outer provider_timestamp_ms to ChainlinkTwapPrice. PMKit then switched from subscribe_raw to the typed 60s helper. A complete 15-minute live paper window preserved the exact boundary E18 value and ran with zero RTDS gaps. This confirms the typed API works for the BTC 15m resolution feed once those two evidence fields are retained.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants