Skip to content

feat: blokli safe channel stake and redemptions - #737

Merged
mjadach-iv merged 7 commits into
mainfrom
feat/blokli-safe-channel-stake-and-redemptions
Aug 17, 2026
Merged

feat: blokli safe channel stake and redemptions#737
mjadach-iv merged 7 commits into
mainfrom
feat/blokli-safe-channel-stake-and-redemptions

Conversation

@mjadach-iv

Copy link
Copy Markdown
Contributor

No description provided.

mjadach-iv and others added 6 commits August 16, 2026 20:56
…tickets

First real use of the per node blokli url. Adds 2 figures the connected node
cannot report on its own:

- wxHOPR staked in the open outgoing channels of every node registered to the
  safe, not just this one
- wxHOPR this node has redeemed on chain, which unlike the node's own ticket
  statistics is not reset when the node database is wiped

src/blokli/ is the client module, playing the role @hoprnet/hopr-sdk plays for
the node slice. Blokli is GraphQL only, at <blokliUrl>/graphql, no auth and open
CORS. 2 things about it are easy to get wrong and are handled here:

- every root field returns a union, and error members come back with HTTP 200,
  so success is decided by __typename, not by the status code
- TokenValueString is neither wei nor a number, it is a formatted decimal with
  the symbol appended ("2084.003187159723402252 wxHOPR"). parseTokenValue splits
  it and converts through viem parseUnits, never through Number, which would
  lose precision at 18 decimals

The url is joined by appending /graphql rather than with new URL(), because the
base can carry a path and new URL would drop its last segment.

src/store/slices/blokli/ mirrors the node slice file for file, and moves the url
override out of the node slice, so all blokli state lives in one place. Its
reducers guard on nodeAddress the way the node reducers guard on apiEndpoint, so
results arriving after a node switch are dropped. Local storage key moves from
node/blokliUrl/<addr> to blokli/url/<addr>.

channelStats(safeAddress, status: OPEN) sums server side and is source side
only, so it is outgoing only by definition and needs no node enumeration.

wxHOPR: Channels OUT on the info page now shows the safe wide figure. That value
also feeds Total Staked and the sidebar, which duplicated the same calculation
verbatim, so all 3 read one memoized selector and cannot disagree. It falls back
to this node's own channels when blokli is unreachable, so nothing regresses.

The tickets page gains Redeemed value and Redemptions, replacing the commented
out row that read the DB-reset-scoped redeemedValue.

Verified against https://blokli.jura.hoprnet.link/ with safe
0x5CBEf561923e9C45BD5e5Af3Cb3a961B236CEd56 and node
0x2bD383d4ab1379ef58E22BBc3E12d2475D5C9b29: 45 open outgoing channels holding
2136.503187161128055072 wxHOPR, 560.000000014983072483 wxHOPR redeemed over 125
redemptions. Bad address, unreachable host and wrong path all surface as a typed
blokliApiError.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
selectChannelsOutBalance silently substituted the connected node's own channel
total when blokli had no data, so wxHOPR: Channels OUT could show a node-only
number under a label and tooltip that said safe-wide, with nothing on screen to
tell the 2 apart. A blokli figure that quietly becomes a different figure is
worse than no figure, so every blokli backed field now shows "-" when blokli has
no data.

With the fallback gone the selector only returned store.blokli.channelStats.data
unchanged, so it, its memoization and its fromBlokli flag are deleted and the
consumers read the slice directly, like they already do for ticketRedemption.
selectBlokliUrl stays: that combines the override with the url the node reports,
which is a config default, not a data fallback.

Total Staked now adds the safe wide channels, making it the safe's true total
stake, and shows "-" without blokli rather than falling back.

The info page's Channels section gains the 2 amounts side by side, so the node
only figure is visible again next to the safe wide one instead of being implied:

  Outgoing (this node)    from the node api, already summed into
                          balances.data.channels by the getChannels reducer
  Outgoing (safe nodes)   from blokli

Unredeemed wxHOPR and Outgoing (this node) stay on node data by design - blokli
indexes only on chain redemptions and has no unredeemed figure. Those are node
sourced fields, not blokli fields with a fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TableExtended (and DERP) declared styled components inside the render
body, creating a new component type on every render and remounting the
whole subtree. First visible symptom: the Blokli URL field lost focus
after every keystroke.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nges

resetData drops channelStats and ticketRedemption and clears isFetching
so the immediate refetch is not swallowed by the thunks' in-flight
guards. urlInUse records the effective url the figures were fetched
with, and the fulfilled reducers drop late responses from a previous
url, mirroring the existing nodeAddress guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mjadach-iv
mjadach-iv enabled auto-merge (squash) August 17, 2026 13:00
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8f2fdf4b-0a6b-4a5a-9bbf-9ed007c825de


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

🔎 Trivy Security Report

Target Package Installed Severity CVE
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) c-ares 1.34.6-r0 HIGH CVE-2026-33630
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) curl 8.17.0-r1 HIGH CVE-2026-5773
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) curl 8.17.0-r1 HIGH CVE-2026-6276
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) libcrypto3 3.5.6-r0 HIGH CVE-2026-45447
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) libcurl 8.17.0-r1 HIGH CVE-2026-5773
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) libcurl 8.17.0-r1 HIGH CVE-2026-6276
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) libexpat 2.7.5-r0 HIGH CVE-2026-45186
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) libexpat 2.7.5-r0 HIGH CVE-2026-56408
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) libssl3 3.5.6-r0 HIGH CVE-2026-45447
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) libxml2 2.13.9-r0 HIGH CVE-2026-6732
europe-west3-docker.pkg.dev/hoprassociation/docker-images/hopr-admin:4.0.0-rc.3-commit.e2e3714-linux-amd64 (alpine 3.23.4) nghttp2-libs 1.68.0-r0 HIGH CVE-2026-27135

@mjadach-iv mjadach-iv changed the title Feat/blokli safe channel stake and redemptions feat: blokli safe channel stake and redemptions Aug 17, 2026
@mjadach-iv
mjadach-iv disabled auto-merge August 17, 2026 13:16
@mjadach-iv
mjadach-iv merged commit 1407477 into main Aug 17, 2026
5 of 6 checks passed
@mjadach-iv
mjadach-iv deleted the feat/blokli-safe-channel-stake-and-redemptions branch August 17, 2026 13:16
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.

1 participant