user's reward loss because of incorrect rewardsTokens in PirexRewards contract when rewardsTokens are not configured yet or configured incorrectly #242
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
duplicate-271
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L373-L417
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L338-L366
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L739-L816
Vulnerability details
Impact
PirexRewards
contract start trackinggmxBaseReward
andpxGmx
as rewardsToken forpxGmx
andpxGlp
as producerTokens from the begining of contract deployment because this values hardcoded inclaimRewards()
function ofPirexGmx
But those primary rewardTokens didn't get inserted toPirexRewards
contract state from the beginning andowner
should add them later. WhenrewardTokens
state are wrong inPirexRewards
contract (gmxBaseReward
andpxGmx
is not in list), users callingPirexReward.claim()
would lose their rewards because contract setuserStates[user].rewards = 0
. This condition can happen in contract early stage or whenowner
tries to change or updaterewardTokens
. Those primaryrewardTokens
should be hardcoded and added to rewards token list when contract get initialized because their values are hardcoded inPirexGmx
and they should be hardcoded inPirexRewards
too.Proof of Concept
This is function
claim()
code inPirexRewards
contract:As you can see the code transfers all the rewards of user for reward tokens registered for this
producerToken
based on user share of total rewards and also it sets the value ofproducerTokens[producerToken].userStates[user].rewards
as zero(user share of rewards of thisproducerToken
become zero) so if in the moment of calling the functionclaim()
the rewards token list was wrong(some tokens were missing) then user would lose his right to those rewards. Functionclaim()
is callable by others for any user so attacker can call this function for other users and make them lose access to their rewards. the rewards calculation for producer tokenspxGmx, pxGlp
with rewards tokensgmxBaseReward, pxGmx
are done from the beginning of the contract but adding those reward tokens should be done byowner
dynamically so in contract early stage the reward list of those producer tokens are wrong and even in other times whenowner
tries to update the reward list(because of any reason like GMX protocol update or by mistake or ....) the list of rewards would be wrong and user would lose funds if attacker callclaim()
for them. there is no pause mechanism in thePirexRewards
contract to prevent callingclaim()
in those states when rewards lists are wrong.This is
harvest()
code:As you can see it update the state of producer and rewards tokens returned by
PirexGmx.claimRewards()
. This is some part ofclaimRewards()
code inPirexGmx
:As you can see the function works all the time and producer tokens
pxGmx, pxGlp
with rewards tokensgmxBaseReward, pxGmx
are hardcoded in the code so it always return them andharvest()
would always calculate rewards for those tokens. so in this Scenario:owner
deployed contracts but rewards list are not yet updated and it is incorrect for producer tokenspxGmx, pxGlp
. (or whenowner
tries to change or update reward tokens list and list is incorrect in the moment)PirexGmx
and protocol stake them in GMX and start getting reward in GMX.PirexRewards.harvest()
soPirexGmx.claimRewards()
would get rewards from GMX andPirexRewards
would calculate rewards for primary rewards tokens(gmxBaseReward, pxGmx
)PirexRewards.claim(PxGmx/PxGLP, user)
for users and contract would set users share of rewards of those producer tokens to zero but don't transfer any rewards to user because rewards list for those producer tokens are incorrect.As you can see when contract is in some states the logics won't work correctly and users would lose their rewards. contract should protect itself from this type of bugs with on-chain mechanism.
Tools Used
VIM
Recommended Mitigation Steps
add producer tokens
pxGmx, pxGlp
with rewards tokensgmxBaseReward, pxGmx
inPirexRewards
when contract initialize or make sureclaim()
can't be called when reward tokens are not yet configured or in wrong states.The text was updated successfully, but these errors were encountered: