code-423n4 / 2023-07-tapioca-findings

12 stars 9 forks source link

A portion of stargate token rewards earned by StargateStrategy are permanently locked in the contract #805

Open code423n4 opened 1 year ago

code423n4 commented 1 year ago

Lines of code

https://github.com/Tapioca-DAO/tapioca-yieldbox-strategies-audit/blob/05ba7108a83c66dada98bc5bc75cf18004f2a49b/contracts/stargate/StargateStrategy.sol#L236

Vulnerability details

Impact

Stargate token rewards are received during lpStaking.deposit but only accounted for in compound. As a result, token rewards earned during _deposited execution are permanently locked in the contract.

Proof of Concept

In lpStaking.deposit, any unclaimed rewards are transferred to the sender.

// lpStaking.deposit
if (user.amount > 0) {
    uint256 pending = user.amount.mul(pool.accStargatePerShare).div(1e12).sub(user.rewardDebt);
    safeStargateTransfer(msg.sender, pending);
}

In StargateStrategy, this deposit function is called in two places, compound and _stake (called by _deposited).

// _stake()
lpStaking.deposit(lpStakingPid, toStake);
// compound()
lpStaking.deposit(2, 0);

compound contains logic to process any newly acquired reward tokens earned from it's call to lpStaking.deposit.

// compound()
uint256 stgBalanceBefore = stgTokenReward.balanceOf(address(this));
lpStaking.deposit(2, 0);
uint256 stgBalanceAfter = stgTokenReward.balanceOf(address(this));

if (stgBalanceAfter > stgBalanceBefore) {
    uint256 stgAmount = stgBalanceAfter - stgBalanceBefore;

    ISwapper.SwapData memory swapData = swapper.buildSwapData(
        address(stgTokenReward),
        address(wrappedNative),
        stgAmount,
        0,
        false,
        false
    );
    uint256 calcAmount = swapper.getOutputAmount(swapData, "");
    uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%

    swapper.swap(swapData, minAmount, address(this), "");

    uint256 queued = wrappedNative.balanceOf(address(this));
    _stake(queued);
}

_stake on the other hand, does not contain any logic to process reward tokens acquired from lpStaking.deposit.

As a result, since reward tokens are acquired during _deposited execution, but only the tokens acquired during compound execution are actually processed, all tokens acquired during _deposited execution are permanently locked in the contract.

Recommended Mitigation Steps

It is recommended that compound swaps the entire balance of reward tokens rather than just the newly acquired balance.

Assessed type

Token-Transfer

c4-pre-sort commented 1 year ago

minhquanym marked the issue as primary issue

0xRektora commented 1 year ago

Medium severity.

c4-sponsor commented 1 year ago

0xRektora marked the issue as disagree with severity

c4-sponsor commented 1 year ago

0xRektora marked the issue as sponsor confirmed

c4-judge commented 1 year ago

dmvt changed the severity to 2 (Med Risk)

c4-judge commented 1 year ago

dmvt marked the issue as selected for report

c4-judge commented 1 year ago

dmvt changed the severity to 3 (High Risk)

c4-judge commented 1 year ago

dmvt changed the severity to 2 (Med Risk)