Omniscia Tokemak Network Audit
Staking Manual Review Findings
Staking Manual Review Findings
STA-01M: Improper Slashing Error Handling
Type | Severity | Location |
---|---|---|
Logical Fault | Minor | Staking.sol:L369 |
Description:
The slash
mechanism fatally fails if the amount
to be slashed exceeds the availableToSlash
amount which can change between a transaction's submission and a transaction's execution in the network.
Example:
344function slash(345 address[] calldata accounts,346 uint256[] calldata amounts,347 uint256 scheduleIndex348) external override onlyOwner whenNotPaused {349 require(accounts.length == amounts.length, "LENGTH_MISMATCH");350 StakingSchedule storage schedule = schedules[scheduleIndex];351 require(schedule.setup, "INVALID_SCHEDULE");352
353 for (uint256 i = 0; i < accounts.length; i++) {354 address account = accounts[i];355 uint256 amount = amounts[i];356
357 require(amount > 0, "INVALID_AMOUNT");358 require(account != address(0), "INVALID_ADDRESS");359
360 StakingDetails memory userStake = userStakings[account][scheduleIndex];361 require(userStake.initial > 0, "NO_VESTING");362
363 uint256 availableToSlash = 0;364 uint256 remaining = userStake.initial.sub(userStake.withdrawn);365 if (remaining > userStake.slashed) {366 availableToSlash = remaining.sub(userStake.slashed);367 }368
369 require(availableToSlash >= amount, "INSUFFICIENT_AVAILABLE");370
371 userStake.slashed = userStake.slashed.add(amount);372 userStakings[account][scheduleIndex] = userStake;373
374 uint256 totalLeft = userStake.initial.sub((userStake.slashed.add(userStake.withdrawn)));375
376 if (withdrawalRequestsByIndex[account][scheduleIndex].amount > totalLeft) {377 withdrawalRequestsByIndex[account][scheduleIndex].amount = totalLeft;378 }379
380 uint256 voteAmount = totalLeft.sub(381 withdrawalRequestsByIndex[account][scheduleIndex].amount382 );383 bytes32 eventSig = "Slashed";384
385 encodeAndSendData(eventSig, account, scheduleIndex, voteAmount);386
387 tokeToken.safeTransfer(treasury, amount);388
389 emit Slashed(account, amount, scheduleIndex);390 }391}
Recommendation:
We advise better case handling to be introduced here whereby instead of using a require
statement, the value of amount
is set to availableToSlash
if it exceeds it.
Alleviation:
The Tokemak team stated that the function should indeed fatally fail in case the amount slashed mismatches the on-chain balance given that this can also mean the off-chain calculations were performed incorrectly. As a result, we consider this exhibit null.
STA-02M: Unsanitized State Transition
Type | Severity | Location |
---|---|---|
Logical Fault | Minor | Staking.sol:L537-L541 |
Description:
The setEventSend
function should only set the _eventSend
value to true
when the values of the destinations
struct have been set.
Example:
537function setEventSend(bool _eventSendSet) external override onlyOwner {538 _eventSend = _eventSendSet;539
540 emit EventSendSet(_eventSendSet);541}
Recommendation:
We advise such sanitization to be imposed via corresponding require
checks as otherwise almost all functions will become inexecutable.
Alleviation:
The function can now only be executed when the destinations.destinationOnL2
value has been set.
STA-03M: Potentially Incorrect Initialization
Type | Severity | Location |
---|---|---|
Logical Fault | Informational | Staking.sol:L78-L110 |
Description:
The Staking
contract implementation is meant to act as an upgrade to a previously deployed implementation yet its initialize
code appears to not factor this into account.
Example:
78function initialize(79 IERC20 _tokeToken,80 IManager _manager,81 address _treasury,82 address _scheduleZeroNotional83) public initializer {84 __Context_init_unchained();85 __Ownable_init_unchained();86 __Pausable_init_unchained();87
88 require(address(_tokeToken) != address(0), "INVALID_TOKETOKEN");89 require(address(_manager) != address(0), "INVALID_MANAGER");90 require(_treasury != address(0), "INVALID_TREASURY");91
92 tokeToken = _tokeToken;93 manager = _manager;94 treasury = _treasury;95
96 //We want to be sure the schedule used for LP staking is first97 //because the order in which withdraws happen need to start with LP stakes98 _addSchedule(99 StakingSchedule({100 cliff: 0,101 duration: 1,102 interval: 1,103 setup: true,104 isActive: true,105 hardStart: 0,106 isPublic: true107 }),108 _scheduleZeroNotional109 );110}
Recommendation:
We advise the zero-based schedule addition to be re-evaluated as should this logic contract be deployed for an existing deployment, it will not properly initialize the zero-based staking schedule.
Alleviation:
The Tokemak team stated that the code reflects correct behaviour that replaces the previous implementation and ensures a correct state in the new logic upgrade.