Skip to content

Add initial self-delegation check in token handler#655

Merged
fewensa merged 1 commit intoringecosystem:mainfrom
Sigri44:main
Apr 8, 2026
Merged

Add initial self-delegation check in token handler#655
fewensa merged 1 commit intoringecosystem:mainfrom
Sigri44:main

Conversation

@Sigri44
Copy link
Copy Markdown
Contributor

@Sigri44 Sigri44 commented Apr 3, 2026

Fix self-delegate calculation for our community

Signed-off-by: Sigri <sigri44@hotmail.fr>
@boundless-forest
Copy link
Copy Markdown
Collaborator

Please take a review and ensure it not breaks our existing voting power calculation logic. @fewensa

@fewensa
Copy link
Copy Markdown
Collaborator

fewensa commented Apr 8, 2026

What this fixes

This PR fixes a vote-power double-materialization bug in the indexer triggered by a specific event combination: an initial self-delegation and an incoming transfer occurring in the same transaction.

The exact scenario:

  1. An address has never delegated before
  2. It performs its first self-delegation in a transaction (DelegateChanged: 0x0 → self)
  3. The same transaction also delivers an incoming token transfer to that address
  4. By the time the transfer handler runs, the rolling record for the delegate change is already visible

Under this condition, the old logic on main allows both the transfer path and the DeligateVotesChanged path to materialize the self-edge independently, causing relation power and contributor power to be overstated.

How it is fixed

The change is in isTransferToCoveredByDelegateChange(). Previously this function always returned false for the transfer-to direction, meaning an incoming transfer was never considered covered by a same-transaction delegate change.

This PR makes it return true when all three conditions hold:

  • fromDelegate == 0x0 (delegating from the undelegated state)
  • toDelegate == delegator (delegating to self)
  • delegator == transfer.to (the delegator is the recipient of this transfer)

With this in place, storeTokenTransfer() correctly recognizes that the incoming transfer is already covered by the same-transaction initial self-delegation and skips the redundant materialization.

Relationship to #639

This is a narrow follow-up hardening patch after #639. Both target the same general bug family (same-transaction DelegateChanged + Transfer + DelegateVotesChanged interactions) but cover different subcases — they complement rather than replace each other.

Recommendation

The logic change is directionally correct. However the PR is missing a targeted regression test. A focused test case should be added to token-vote-power.test.ts covering the full event sequence of "delegate change before transfer, initial self-delegation", asserting that the final DelegateMapping, Delegate, Contributor, and DataMetric contain no duplicate power accumulation before this is merged.


Regression testing needs to be added.

@fewensa fewensa merged commit bc116bd into ringecosystem:main Apr 8, 2026
fewensa added a commit that referenced this pull request Apr 8, 2026
* test(indexer): cover initial self-delegation ordering

* test(indexer): strengthen self-delegation regression assertions

* test(indexer): lock delegate effective-count transitions
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.

3 participants