# Tokens that are both bribes and StakeDao gauge rewards will cause loss of funds

SdtBuffer returns bribe and gauge reward tokens as a concatenated list without dedup; SdtStakingPositionService overwrites duplicate entries, permanently losing one token's rewards.

- Payout: Contest reward
- Severity: high
- Program: Convergence
- Credited: 0x52
- Disclosed: 2023-11-06
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-11-convergence-judging/issues/182
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-11-convergence%3AH-3
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** SdtStakingPositionService / SdtBuffer reward accounting
**Root cause:** pullRewards concatenates gauge reward tokens and bribe tokens without deduplicating; the consumer writes _sdtRewardsByCycle[cycle][erc20Id] with assignment instead of incrementing, so a token appearing twice overwrites the first amount.
**Steps:**
1. SdtBuffer.pullRewards builds tokenAmounts of size rewardAmount + bribeTokens.length, appending gauge reward_tokens then bribeTokens with no duplicate check.
2. SdtStakingPositionService loops _rewardAssets and maps token to erc20Id via _tokenToId.
3. For a token that is both a bribe and a gauge reward, the same erc20Id is hit twice.
4. `_sdtRewardsByCycle[cycle][erc20Id] = TokenAmount(token, amount)` overwrites the first entry with the second amount.
5. First occurrence's amount is never distributed and is lost.
**How found:** Code reading of the reward-pull flow: noticed the returned array is a concatenation of two sources with no dedup, then traced the consumer's assignment (not increment) into the per-cycle mapping, concluding duplicates overwrite.
**Insight:** When a function returns a concatenated list from multiple sources, check the consumer's storage write: assignment into a keyed mapping silently drops duplicate keys, unlike an increment or sum.
