Lucene search

K
code423n4Code4renaCODE423N4:2023-07-RESERVE-FINDINGS-ISSUES-33
HistoryAug 04, 2023 - 12:00 a.m.

StargateRewardableWrapper._claimAssetRewards should use stakingContract.withdraw(poolId, 0)

2023-08-0400:00:00
Code4rena
github.com
10
stargaterewardablewrapper
claim rewards
security vulnerability
deposit
withdraw
stakingcontract

AI Score

6.9

Confidence

Low

Lines of code

Vulnerability details

Impact

StargateRewardableWrapper._claimAssetRewards leverage stakingContract.deposit(poolId, 0); to claim rewards from Stargate. But it could fail to claim the reward in the edge case.

Proof of Concept

StargateRewardableWrapper._claimAssetRewards calls stakingContract.deposit(poolId, 0); to claim the rewards.
<https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/stargate/StargateRewardableWrapper.sol#L48&gt;

    function _claimAssetRewards() internal override {
        stakingContract.deposit(poolId, 0);
    }

But stakingContract.deposit(poolId, 0) won’t transfer the pending reward if user.amount == 0
<https://github.com/stargate-protocol/stargate/blob/main/contracts/LPStaking.sol#L159&gt;

    function deposit(uint256 _pid, uint256 _amount) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        updatePool(_pid);
        if (user.amount &gt; 0) {
            uint256 pending = user.amount.mul(pool.accStargatePerShare).div(1e12).sub(user.rewardDebt);
            safeStargateTransfer(msg.sender, pending);
        }
        pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
        user.amount = user.amount.add(_amount);
        user.rewardDebt = user.amount.mul(pool.accStargatePerShare).div(1e12);
        lpBalances[_pid] = lpBalances[_pid].add(_amount);
        emit Deposit(msg.sender, _pid, _amount);
    }

On the other hand, stakingContract.withdraw(poolId, 0) would transfer the pending reward when user.amount == 0
<https://github.com/stargate-protocol/stargate/blob/main/contracts/LPStaking.sol#L174&gt;

    function withdraw(uint256 _pid, uint256 _amount) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount &gt;= _amount, "withdraw: _amount is too large");
        updatePool(_pid);
        uint256 pending = user.amount.mul(pool.accStargatePerShare).div(1e12).sub(user.rewardDebt);
        safeStargateTransfer(msg.sender, pending);
        user.amount = user.amount.sub(_amount);
        user.rewardDebt = user.amount.mul(pool.accStargatePerShare).div(1e12);
        pool.lpToken.safeTransfer(address(msg.sender), _amount);
        lpBalances[_pid] = lpBalances[_pid].sub(_amount);
        emit Withdraw(msg.sender, _pid, _amount);
    }

Tools Used

Manual Review

Recommended Mitigation Steps

Use stakingContract.withdraw instead of stakingContract.deposit

    function _claimAssetRewards() internal override {
+       stakingContract.withdraw(poolId, 0);
-       stakingContract.deposit(poolId, 0);
    }

Assessed type

Other


The text was updated successfully, but these errors were encountered:

All reactions

AI Score

6.9

Confidence

Low