RdpxV2Core.removeAssetFromtokenReserves(...)
irrecoverably breaks reserve token handling
#717
Labels
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
duplicate-33
edited-by-warden
grade-c
QA (Quality Assurance)
Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L266-L290
Vulnerability details
Vulnerability Details
The
reserveTokens
storage array is not updated on removing a reserve token by calling RdpxV2Core.removeAssetFromtokenReserves(...), see diff in Recommended Mitigation Steps.This corrupts the
reservesIndex
storage mapping as described in the following.Initial state
Assume the reserve tokens 0x1 - AAA, 0x2 - BBB, 0x3 - CCC and 0x4 - DDD were gracefully added via RdpxV2Core.addAssetTotokenReserves(...) resulting in the state below.
State after removing token CCC
After the removal of token 0x3 - CCC via RdpxV2Core.removeAssetFromtokenReserves(...), the
reserveTokens
array still holds the value CCC instead of DDD since it was never updated. The state is already partially corrupted here.State after removing token BBB
After the removal of token 0x2 - BBB via RdpxV2Core.removeAssetFromtokenReserves(...), the following state issues can be observed:
reserveTokens
array still holds the value BBB instead of DDD since it was never updated.reservesIndex
mapping and points to asset 0x4 - DDD.reservesIndex
entry for token DDD is now detached and points to a non-existing index, i.e. the reserve cannot be accessed via thereservesIndex
mapping anymore.The state is now severely corrupted and it gets worse with each additional reserve token removal.
For comparison, here is how the state table should look like at this point:
Impact
As a consequence of the above, the
reservesIndex
mapping can be corrupted in 2 ways:However, the
reservesIndex
mapping is used at 20 instances troughout the RdpxV2Core contract involving purchase of options, staking, transfers, bonding, settlement, funding, holding the peg and the getReserveTokenInfo(...) method which serves external contracts.Furthermore, inability to remove a reserve token from the
reserveAsset
array due to itsreservesIndex
entry being corrupted/detached leads to DoS of the sync() method in case of token contract failure, which subsequently affects the calling ReLPContract.reLP(...) method.According to the full product spec which was linked in the README:
Therefore, it is likely that secondary reserve tokens are added and removed during the lifecycle of the protocol which is sufficient to facilitate this vulnerability.
Moreover, even the primary reserves might be removed and re-added in case of migration to a new token contract due to e.g. an uncovered vulnerability. This seems to be an intended use case, otherwise the primary reserve addresses would be immutable instead of being looked up trough a storage array via a mapping which is very costly, e.g.
reserveAsset[reservesIndex["RDPX"]].tokenAddress
. (It would not be the first time that such emergency actions have to be taken by a DeFi protocol.)Depending on which reserve tokens are actually affected by the corruption of the
reservesIndex
mapping, the possible impacts are ranging from DoS concerning interactions with the affected reserves (i.e. slight depeg due to secondary reserves being unavailable through mapping or point to wrong asset) to total failure of the protocol by full DoS of the core functionalities (i.e. severe depeg due to primary reserves being unavailable through mapping or point to wrong asset).Proof of Concept
The following test case
testAddRemoveTokenReserves()
proves the discussed vulnerability and is replicating the same states as shown by the tables above.Just apply the diff below and run the test with
forge test -vv --match-test testAddRemoveTokenReserves
:Tools Used
Manual Review
Recommended Mitigation Steps
In order to mitigate all the discussed issues, the
reserveTokens
array needs to be updated on reserve token removal:Assessed type
Error
The text was updated successfully, but these errors were encountered: