Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitter Crepe Lizard - Incorrect Approval Amount for WrsETH Withdrawal Leading to Potential Transaction Failures #1051

Open
sherlock-admin3 opened this issue Dec 30, 2024 · 0 comments

Comments

@sherlock-admin3
Copy link
Contributor

Bitter Crepe Lizard

High

Incorrect Approval Amount for WrsETH Withdrawal Leading to Potential Transaction Failures

Summary

In the transferFundsToGlobal function of the Treasury contract, there is a critical issue where the approval amount for WrsETH withdrawal uses the wrong index from the transferAmounts array. The function approves transferAmounts[1] (WeETH amount) instead of transferAmounts[2] (WrsETH amount) when handling WrsETH withdrawals, potentially leading to transaction failures or excessive approvals.

Root Cause

The root cause is a logical error in the approval call within the WrsETH handling block:
Treasury.sol#L782-L783

function transferFundsToGlobal(
        uint256[4] memory transferAmounts
    ) external onlyCoreContracts {
        // Loop through the array to transfer all amounts
        for (uint8 i = 0; i < 4; i++) {
            if (transferAmounts[i] > 0) {
                address assetAddress = borrow.assetAddress(IBorrowing.AssetName((i == 3 ? 4 : i) + 1));
                if (i != 0) {
                    if (i == 2) {
@>                      if (!IWrsETH(assetAddress).approve(assetAddress, transferAmounts[1])) revert Treasury_ApproveFailed();
                        IWrsETH(assetAddress).withdraw(borrow.assetAddress(IBorrowing.AssetName.rsETH), transferAmounts[2]);
                        assetAddress = borrow.assetAddress(IBorrowing.AssetName.rsETH);
                    }
                    bool success = IERC20(assetAddress).transfer(msg.sender, transferAmounts[i]); 
                    if (!success) revert Treasury_TransferFailed();
                } else {
                    (bool sent, ) = payable(msg.sender).call{value: transferAmounts[i]}(""); 
                    require(sent, "Failed to send Ether");
                }
            }
        }
    }

The code incorrectly uses transferAmounts[1] (WeETH amount) instead of transferAmounts[2] (WrsETH amount) for the approval.

if (!IWrsETH(assetAddress).approve(assetAddress, transferAmounts[1])) revert Treasury_ApproveFailed();

Internal pre-conditions

  1. The function must be called by a core contract (enforced by onlyCoreContracts modifier)
  2. transferAmounts[2] (WrsETH amount) must be greater than 0
  3. The contract must be processing index 2 in the loop (WrsETH handling)

External pre-conditions

  1. The Treasury contract must have sufficient WrsETH balance

Attack Path

  1. A core contract calls transferFundsToGlobal with different amounts for WeETH and WrsETH
  2. When i == 2 (WrsETH processing):
  • If transferAmounts[1] (WeETH) < transferAmounts[2] (WrsETH)
    • The approval amount will be insufficient
    • The subsequent withdrawal will fail

Impact

If WeETH amount is less than WrsETH amount, withdrawals will fail

PoC

No response

Mitigation

// Replace this line:
if (!IWrsETH(assetAddress).approve(assetAddress, transferAmounts[1])) revert Treasury_ApproveFailed();

// With:
if (!IWrsETH(assetAddress).approve(assetAddress, transferAmounts[2])) revert Treasury_ApproveFailed();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant