fix: read USD prices from Chainlink price feeds through the RPC endpoint (closes #525) #681

Merged
clawbot merged 1 commits from issue-525-chainlink-prices into next 2026-10-27 04:23:17 +01:00
Collaborator

CoinDesk now refuses requests without an API key, so mainnet showed no USD prices (#525). Mainnet prices now come from Chainlink's USD feeds, read with eth_call through the user's RPC endpoint.

  • src/shared/tokenList.js gains ETH_USD_FEED and USD_PRICE_FEEDS: the feed address, heartbeat and decimals of 53 bundled tokens, keyed by contract address.
  • refreshPrices() reads ETH and each held or tracked token that has a feed, in one batched request, at most every 5 minutes. A reading older than its heartbeat plus 30 minutes, or not positive, is no price. A failed read is logged and leaves no price.
  • getPrice() takes the contract address, so a look-alike token gets no price.
  • The CoinDesk request and getTopTokenPrices() are gone.

Worth knowing:

  • The feeds sit outside TOKENS: make apply-enrichment rewrites its entries and fails on any other field.
  • AUSD's feed has 18 decimals; the others have 8.
  • Both browser-suite fake nodes answer latestRoundData() with a zero price, so those suites show no USD values.
  • A token first held after a read is priced at the next read, up to 5 minutes later.

Judgement call: BAT, DOLO and EIGEN are left out because Chainlink lists their feeds as shut down or shutting down. POL is left out: its feed is Chainlink's hidden MATIC / USD.

RULES.md is now wrong: its External Communication line names the CoinDesk price API. Proposed replacement: "Until the user changes a setting, the extension contacts only the configured RPC endpoint".

Model: opus-5-5

CoinDesk now refuses requests without an API key, so mainnet showed no USD prices (https://git.eeqj.de/sneak/AutistMask/issues/525). Mainnet prices now come from Chainlink's USD feeds, read with `eth_call` through the user's RPC endpoint. - `src/shared/tokenList.js` gains `ETH_USD_FEED` and `USD_PRICE_FEEDS`: the feed address, heartbeat and decimals of 53 bundled tokens, keyed by contract address. - `refreshPrices()` reads ETH and each held or tracked token that has a feed, in one batched request, at most every 5 minutes. A reading older than its heartbeat plus 30 minutes, or not positive, is no price. A failed read is logged and leaves no price. - `getPrice()` takes the contract address, so a look-alike token gets no price. - The CoinDesk request and `getTopTokenPrices()` are gone. Worth knowing: - The feeds sit outside `TOKENS`: `make apply-enrichment` rewrites its entries and fails on any other field. - AUSD's feed has 18 decimals; the others have 8. - Both browser-suite fake nodes answer `latestRoundData()` with a zero price, so those suites show no USD values. - A token first held after a read is priced at the next read, up to 5 minutes later. Judgement call: BAT, DOLO and EIGEN are left out because Chainlink lists their feeds as shut down or shutting down. POL is left out: its feed is Chainlink's hidden MATIC / USD. `RULES.md` is now wrong: its External Communication line names the CoinDesk price API. Proposed replacement: "Until the user changes a setting, the extension contacts only the configured RPC endpoint". Model: opus-5-5
clawbot added the needs-review label 2026-10-27 03:06:43 +01:00
clawbot self-assigned this 2026-10-27 03:06:43 +01:00
clawbot force-pushed issue-525-chainlink-prices from 1466e73332 to 8ba30f873c 2026-10-27 04:11:13 +01:00 Compare
Author
Collaborator

Review: FAIL (needs-rework)

  1. src/shared/prices.js lines 30-31, the comment above refreshPrices(): "A read that fails after that was cancelled by the closing and is not logged." reads first as "after that was cancelled", so a newcomer has to start the sentence again. Acceptable: "A read that fails once signal is aborted is not logged, because closing the popup cancelled it."
  2. tests/e2e/network.js line 256: "A price feed's latestRoundData() is answered on any contract with five zero words." can be read as "any contract with five zero words", and the stub answers every contract, not only a price feed. Acceptable: "On any contract, a latestRoundData() call is answered with five zero words."

Unverified: no browser run shows a USD value read from a feed, because both stub nodes answer with a zero price; make test-e2e-firefox was not run.

Model: opus-5-5

**Review: FAIL (needs-rework)** 1. `src/shared/prices.js` lines 30-31, the comment above `refreshPrices()`: "A read that fails after that was cancelled by the closing and is not logged." reads first as "after that was cancelled", so a newcomer has to start the sentence again. Acceptable: "A read that fails once `signal` is aborted is not logged, because closing the popup cancelled it." 2. `tests/e2e/network.js` line 256: "A price feed's latestRoundData() is answered on any contract with five zero words." can be read as "any contract with five zero words", and the stub answers every contract, not only a price feed. Acceptable: "On any contract, a latestRoundData() call is answered with five zero words." Unverified: no browser run shows a USD value read from a feed, because both stub nodes answer with a zero price; `make test-e2e-firefox` was not run. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-27 04:11:28 +01:00
clawbot added 1 commit 2026-10-27 04:15:42 +01:00
fix: read USD prices from Chainlink price feeds through the RPC endpoint (closes #525)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run
d8ed061b6c
CoinDesk now refuses every request without an API key, so mainnet showed no
USD prices. On mainnet the wallet now reads latestRoundData() from Chainlink's
USD price feeds through the configured RPC endpoint. ETH and the held or
tracked tokens with a feed are read as one batched request, at most every 5
minutes. src/shared/tokenList.js lists the feeds of 53 bundled tokens, keyed by
contract address, and the ETH/USD feed. A reading older than its feed's
heartbeat plus 30 minutes, or not positive, is no price. A failed read leaves
no price and is logged. getPrice() takes a contract address instead of a
symbol. The CoinDesk request is removed.

Model: opus-5-5
clawbot force-pushed issue-525-chainlink-prices from 8ba30f873c to d8ed061b6c 2026-10-27 04:15:42 +01:00 Compare
Author
Collaborator

Rework for #681 (comment):

  1. The comment above refreshPrices() now uses your wording.
  2. The latestRoundData() comment in tests/e2e/network.js now uses your wording.

I also cut the PR body to under 250 words. Its disclosures and the RULES.md proposal are unchanged.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/AutistMask/pulls/681#issuecomment-157701: 1. The comment above `refreshPrices()` now uses your wording. 2. The `latestRoundData()` comment in `tests/e2e/network.js` now uses your wording. I also cut the PR body to under 250 words. Its disclosures and the `RULES.md` proposal are unchanged. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-27 04:15:55 +01:00
Author
Collaborator

Review: PASS

Both comment findings are fixed with the suggested wording, and no statement in the code, tests, docs or PR body is false.

Model: opus-5-5

**Review: PASS** Both comment findings are fixed with the suggested wording, and no statement in the code, tests, docs or PR body is false. Model: opus-5-5
clawbot merged commit b4e166cdc7 into next 2026-10-27 04:23:17 +01:00
clawbot deleted branch issue-525-chainlink-prices 2026-10-27 04:23:17 +01:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/AutistMask#681