Omniscia Colony Lab Audit

AuthorizedStaking Manual Review Findings

AuthorizedStaking Manual Review Findings

ASG-01M: Improper Increase of Registered Tokens

Description:

The _restake function improperly increases the registered tokens in case both the from and to address are registered, such as during a self-transfer.

Example:

contracts/StakingV2/AuthorizedStaking.sol
256/**
257 * @notice Restakes tokens with the authorization limitations
258 * @dev Covers stake and both restake partial and restake all
259 */
260function _restake(address from, address to, uint256 amount) internal virtual override {
261 // stake conditions for accounts could be different
262 require(
263 stakeBalanceOf(to) + amount >= accountAuthorizedAmount(to),
264 "not enough for authorization"
265 );
266
267 _decreaseTotalRegisteredTokens(from, amount);
268
269 // restake all
270 if (amount == stakeBalanceOf(from)) {
271 _unregisterAccount(from);
272 } else {
273 // restake partial
274 require(
275 stakeBalanceOf(from) >= amount + accountAuthorizedAmount(from),
276 "amount breaks authorization"
277 );
278 }
279
280 // save conditions before actual stake,
281 // expect: deposits[account] == 0
282 _saveInitialConditions(to);
283
284 super._restake(from, to, amount);
285
286 _increaseTotalRegisteredTokens(to, amount);
287}

Recommendation:

We advise the accounting system to be corrected as it is currently broken.

Alleviation:

The contract's logic has been relocated to the StakingV2.sol file and has been properly alleviated by introducing an if clause that stops execution if the from and to addresses are equivalent.

ASG-02M: Inexistent Subtraction of Registered Tokens

Description:

Whenever an account is unregistered, their tokens remain accounted for in the totalRegisteredStake incorrectly.

Example:

contracts/StakingV2/AuthorizedStaking.sol
213/**
214 * @dev Decrease registered tokens only for registered accounts
215 */
216function _decreaseTotalRegisteredTokens(address account, uint256 amount) internal {
217 if (isAccountRegistered(account)) {
218 totalRegisteredStake -= amount;
219 }
220}
221
222/**
223 * @notice Makes account unregistered
224 * @dev Also deletes account initialStakeConditions
225 *
226 * Emits a {Unregistered} event for authorized accounts
227 */
228function _unregisterAccount(address account) internal {
229 delete initialStakeConditions[account];
230
231 if (isAccountRegistered(account)) {
232 registered[account] = false;
233 emit Unregistered(account);
234 }
235}

Recommendation:

We advise them to be properly decremented by a corresponding call during the _unregisterAccount function's execution.

Alleviation:

The contract's logic was relocated to the StakingV2.sol file and the logic has been updated to properly decrement the totalRegisteredStake variable thereby alleviating this exhibit.

ASG-03M: Inexplicable Capability of Re-Invocation

Description:

The migrator and stakingV1Contract variables of the contract are powerful and should be assigned only once.

Example:

contracts/StakingV2/AuthorizedStaking.sol
335/**
336 * @notice Allows to set new migrator address
337 * @param newMigrator Address of the new migrator
338 *
339 * Emits a {MigratorChanged} event
340 */
341function setMigrator(address newMigrator) external onlyOwner {
342 migrator = newMigrator;
343 emit MigratorChanged(newMigrator);
344}

Recommendation:

We advise the functions to prevent re-invocation by imposing a corresponding require check.

Alleviation:

The contract's logic has been relocated to the StakingV2.sol contract and the migrator as well as the stakingV1Contract can both be set once thereby alleviating this exhibit in full.