31381 - [SC - Low] Alchemix Incorrect Initialisation of struct in...
Submitted on May 17th 2024 at 19:51:58 UTC by @Norah for Boost | Alchemix
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
Description
Brief/Intro
In the
_checkpoint()
routine of thevoterEscrow
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.
Vulnerability Details
The problem here is that
initialLastPoint
andlastPoint
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).
Impact Details
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.
Recomendation
Initialized a new struct for the initialLastPoint in parallel with lastPoint instead of assigning it.
Proof of Concept
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 namesRun 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).
Last updated