Summary
The storage layout is different between LevelOne and LevelTwo.
Vulnerability Details
There's missing schoolFees
variable and will causing incorrect variable overwrite after the contract upgrade.
The followings are the 2 contract storage layout to demonstrate the inconsistant.
LevelOne.sol
address principal;
bool inSession;
uint256 schoolFees;
uint256 public immutable reviewTime = 1 weeks;
uint256 public sessionEnd;
uint256 public bursary;
uint256 public cutOffScore;
mapping(address => bool) public isTeacher;
mapping(address => bool) public isStudent;
mapping(address => uint256) public studentScore;
mapping(address => uint256) private reviewCount;
mapping(address => uint256) private lastReviewTime;
address[] listOfStudents;
address[] listOfTeachers;
uint256 public constant TEACHER_WAGE = 35;
uint256 public constant PRINCIPAL_WAGE = 5;
uint256 public constant PRECISION = 100;
IERC20 usdc;
LevelTwo.sol
address principal;
bool inSession;
uint256 public sessionEnd;
uint256 public bursary;
uint256 public cutOffScore;
mapping(address => bool) public isTeacher;
mapping(address => bool) public isStudent;
mapping(address => uint256) public studentScore;
address[] listOfStudents;
address[] listOfTeachers;
uint256 public constant TEACHER_WAGE_L2 = 40;
uint256 public constant PRINCIPAL_WAGE_L2 = 5;
uint256 public constant PRECISION = 100;
IERC20 usdc;
Impact
Different storage layout will cause dangerous logic issue and impact the business logic within the contract.
Tools Used
Manual review
Recommendations
Considering make sure the variables between 2 contracts are exactly the same.