maxWithdraw() and maxRedeem() doesn't return correct value which can make other contracts fail while working with protocol #476
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
fix token (sponsor)
Token related fix, should be fixed prior to launch
M-16
selected for report
This submission will be included/highlighted in the audit report
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Lines of code
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L215-L223
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L205-L213
Vulnerability details
Impact
Functions
maxWithdraw()
andmaxRedeem()
returns max amount of assets or shares owner would be able to withdraw taking into account liquidity in the TokenggAVAX contract, but logics don't consider that when user withdraws the withdrawal amounts subtracted fromtotalReleasedAssets
(inbeforeWithdraw()
function) so the maximum amounts that can user withdraws should always be lower thantotalReleasedAssets
(which shows all the deposits and withdraws) but because functionsmaxWithdraw()
andmaxRedeem()
usestotalAssets()
to calculate available AVAX which includes deposits and current cycle rewards so those functions would return wrong value (whenever the return value is bigger thantotalReleaseAssets
then it would be wrong)Proof of Concept
This is
beforeWithdraw()
code:This is
beforeWithdraw()
code which is called whenever users withdraws their funds and as you can see the amount of withdrawal assets subtracted fromtotalReleaseAssets
so withdrawal amounts can never be bigger thantotalReleaseAssets
. This ismaxWithdraw()
code:As you can see to calculate available AVAX in the contract address code uses
totalAssets() - stakingTotalAssets
andtotalAssets()
shows deposits + current cycle rewards sototalAssets()
is bigger thantotalReleaseAssets
and the value of thetotalAssets() - stakingTotalAssets
can be bigger thantotalReleaseAssets
and if code returnsavail
as answer then the return value would be wrong.imagine this scenario:
totalReleaseAssets
is10000
AVAX.stakingTotalAssets
is1000
AVAX.4000
AVAX andblock.timestamp
is currently in the middle of the cycle so current rewards is2000
AVAX.totalAssets()
istotalReleaseAssets + current rewards = 10000 + 2000 = 12000
.10000 + 4000 - 1000 = 13000
AVAX.maxWithdraw()
and code would calculate user assets as10800
AVAX and available AVAX in contract astotalAssets() - stakingTotalAssets = 12000 - 1000 = 11000
and code would return10800
as answer.10800
AVAX code would revert in the functionbeforeWithdraw()
because code would try to executetotalReleaseAssets = totalReleaseAssets - amount = 10000 - 10800
and it would revert because of the underflow. so in reality user1 couldn't withdraw10800
AVAX which was the return value of themaxWithdraw()
for user1.the root cause of the bug is that the withdrawal amount is subtracted from
totalReleaseAssets
and so max withdrawal can never betotalReleaseAssets
and functionmaxWithdraw()
should never return value bigger thantotalReleaseAssets
. (the bug in functionmaxRedeem()
is similar)This bug would cause other contract or front end calls to fail, for example if the logic is something like this:
according the function definitions this code should work bug because of the the issue there are situations that this would revert and other contracts and UI can't work properly with the protocol.
Tools Used
VIM
Recommended Mitigation Steps
consider
totalReleaseAssets
in max withdrawal amount too.The text was updated successfully, but these errors were encountered: