Closed sherlock-admin2 closed 6 months ago
1 comment(s) were left on this issue during the judging contest.
takarez commented:
valid because { The watson was able to explain the flaw in the implementation of the balances array that stores the balance corresponding to a specific user; but its also a dupp of 109}
VAD37
high
Burn
CouncilMember
NFT mixed up rewards balance of other NFT members. Causing wrong rewards to userSummary
CouncilMember.sol
use unique NFT ID as index for arraybalances[]
. NFT ID start from 0 and counting up to total NFT minted. So using NFT ID as index is safe as long as it share same length and never changing order.But the burn NFT function swapping
balances[]
burning ID array index with the last element of array and popping last element from array.Causing array out of order, not sorted same as by NFT ID. And
balances[]
length is not the same as total NFT minted anymore.This result in last person minted NFT cannot claim rewards anymore as their NFT ID now higher than
balances[]
length. Also 1 person lost rewards as their NFT ID is swapped with the burning NFT ID.Vulnerability Detail
Look at how NFT is minted
NFT ID is used as array index to keep track of rewards balance for each NFT. Each NFT is council member. The above implementation have a problem that
balances[]
and NFT ID must counting incremented and fixed order.Just so when someone claim rewards, contract know which NFT owner to send rewards to. Using NFT ID as index to find rewards balance. https://github.com/sherlock-audit/2024-01-telcoin/blob/main/telcoin-audit/contracts/sablier/core/CouncilMember.sol#L92-L111
But the burn function while sending NFT to burn address, it also removing an index
balances[]
array by popping the last element.By swap the burning NFT ID with the last element of array
balances[]
, the array is now out of order andbalances[]
length is not the same as total NFT minted anymore. https://github.com/sherlock-audit/2024-01-telcoin/blob/main/telcoin-audit/contracts/sablier/core/CouncilMember.sol#L210-L222This simply result in someone else balance is now swapped with the burning NFT balances which is 0.
Even the last NFT minted member cannot claim rewards anymore as their NFT ID now higher than
balances[]
length.Impact
After a NFT is burned, lost rewards for a member of council. Also last NFT minted member cannot claim rewards anymore.
Code Snippet
https://github.com/sherlock-audit/2024-01-telcoin/blob/main/telcoin-audit/contracts/sablier/core/CouncilMember.sol#L173-L182 https://github.com/sherlock-audit/2024-01-telcoin/blob/main/telcoin-audit/contracts/sablier/core/CouncilMember.sol#L92-L111 https://github.com/sherlock-audit/2024-01-telcoin/blob/main/telcoin-audit/contracts/sablier/core/CouncilMember.sol#L210-L222
Tool used
Manual Review
Recommendation
Here is a quick fix without changing much of the code.
Do not pop
balances[]
array when burning NFT.Along with counter to keep track of total NFT minted and total NFT burned. Rewards divide evenly among NFT not burned yet. The
_retrieve()
function that spread rewards evenly should check if NFT is burned or not before sending rewards. Usingbalances[]
array length as NFT ID.Duplicate of #199