31381 - [SC - Low] Alchemix Incorrect Initialisation of struct in...
Last updated
Was this helpful?
Last updated
Was this helpful?
Submitted on May 17th 2024 at 19:51:58 UTC by @Norah for
Report ID: #31381
Report type: Smart Contract
Report severity: Low
Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/VotingEscrow.sol
Impacts:
Contract fails to deliver promised returns, but doesn't lose value
In the _checkpoint()
routine of the voterEscrow
contract, the Global Point (pointHistory[epoch]) for all previous epochs is updated within a for loop.
For this, a memory struct called lastPoint
is initialised with the last global point or with zero values of bias and slope, along with the latest timestamp and block number, in case it is called in the first epoch.
Another struct, initialLastPoint
, is also initialised by directly assigning the previously declared lastPoint
This loop begins with the timestamp of the last Global checkpoint and increments by weeks with each iteration.
The global point is updated at corresponding times with appropriate bias and slope in each iteration.
For the block number, it is extrapolated on a line with the current time and block number as endpoints, using the last recorded values in initialLastPoint
as the starting point.
The problem here is that initialLastPoint
and lastPoint
both are pointing to the same struct in memory, instead of initialLastPoint pointing to a separate copy of it.
As a result, the entire calculation for updating the block number becomes incorrect.
Since the values of _time and initialLastPoint.ts will be the same, as _time is read from lastPoint, which again points to the same struct as initialLastPoint.
Therefor, in each iteration, lastPoint.blk will evaluate to the same initialLastPoint.blk. (as assigned initially).
The vulnerability results in incorrect block numbers being assigned, specifically the last recorded blockNnumber of the global point, will be assigned to all the the new points being updated.
All the functionalities relaying on the totalVoting voter power at particular block.number will be catch incorrect values.
Initialized a new struct for the initialLastPoint in parallel with lastPoint instead of assigning it.
I have attached POC using the existing test suite show casing the impact of vulnerability.
I have also attached additional test with simplified code of _checkpoint()
, showcasing how both struct are pointing to the same struct instance in memory.
To Run the tests add them (along with struct declaration) into the file votingEscrow.t.sol
use command with following with respective names
Run via command : "forge test --fork-url https://eth-mainnet.g.alchemy.com/v2/{Alchemy API Key} --match-test "testIncorrectBlockNumber" -vv"
I have attached the screenshot of output of both the tests in the attachments.
Note : Before running the test ensure that constant MULTIPLIER in the VotingEscrow is updated to 1e18,to avoid the impact due to another bug in the same functionality,(check Report #31234 for more detail).