stake.link

stake.link
DeFiHardhatBridge
27,500 USDC
View results
Submission Details
Severity: high
Invalid

Dynamic Conversion Rate Miscalculation in WrappedTokenBridge Contract. _transferTokens() #L168

Summary

The WrappedTokenBridge contract incorrectly assumes a static 1:1 conversion rate when calculating the amount of wrapped tokens (wSDToken) to transfer after wrapping the original tokens (sdToken). This assumption leads to potential discrepancies due to the dynamic nature of the conversion rate, which is influenced by the changing state of the staking pool.

Vulnerability Details

The _transferTokens method within the WrappedTokenBridge contract calculates the amountToTransfer by measuring the balance change of wSDToken before and after the wrapping operation. This method does not consider the actual conversion rate provided by the WrappedSDToken contract's getSharesByStake function, which dynamically calculates the number of shares based on the current totalShares and totalStaked.

Impact

The _transferTokens method may incorrectly calculate the amountToTransfer due to not accounting for the dynamic conversion rate between staked sdToken and wSDToken shares. This can lead to users receiving fewer wrapped tokens on the destination chain than the number of original tokens they intended to transfer, causing financial discrepancies and undermining the integrity of cross-chain transfers. Additionally, the TokensTransferred event may log incorrect amounts, causing confusion and potentially affecting off-chain tracking and analytics.

##POC:

The WrappedTokenBridge contract interacts with a WrappedSDToken contract to wrap sdToken into wSDToken.

The WrappedSDToken contract has a getSharesByStake function that determines the number of wSDToken shares to mint based on the current totalShares and the total amount staked (totalStaked).

The getSharesByStake function calculates the number of shares (wSDToken) that corresponds to a staked amount (_amount) of sdToken. The calculation is based on the proportion of _amount to the totalStaked, multiplied by totalShares.

The _transferTokens method in the WrappedTokenBridge contract does not account for this calculation and assumes a 1:1 conversion rate.

  1. Initial State: Assume totalShares is 10,000 and totalStaked is 10,000 sdToken, which implies a 1:1 ratio of staked tokens to shares.

  2. User Action: A user wants to wrap 1,000 sdToken and initiates the process.

  3. Conversion Calculation: The getSharesByStake function is called with _amount of 1,000 sdToken. Since totalStaked is not zero, the function calculates the shares as (1,000 * 10,000) / 10,000, which equals 1,000 shares.

  4. Change in Ratios: Now assume that totalStaked increases to 20,000 sdToken while totalShares remains 10,000 due to other users staking tokens without wrapping. The ratio of staked tokens to shares changes.

  5. New User Action: Another user wants to wrap 1,000 sdToken.

  6. Incorrect Calculation: The getSharesByStake function now calculates the shares as (1,000 * 10,000) / 20,000, which equals 500 shares. However, the _transferTokens method still assumes a 1:1 conversion and incorrectly calculates the amountToTransfer as 1,000 shares.

  7. Result: The user receives 500 shares on the destination chain instead of the expected 1,000, leading to a discrepancy.

Tools Used

Manual review

Recommendations

Return Values from Wrap Functions: Update the wrap function in the WrappedSDToken contract to return the actual amount of wrapped tokens minted, and use this return value to set amountToTransfer.

Use Actual Conversion Rate:

The method should use the actual conversion rate from getSharesByStake to determine the correct amount of wrapped tokens to transfer.

uint256 amountToTransfer = wrappedSDToken.getSharesByStake(_amount);

In the _transferTokens method of the WrappedTokenBridge contract, the focus is on the conversion process during the wrapping of tokens, not on querying individual balances. Therefore, the getSharesByStake function is used to calculate the correct amount of shares to mint based on the staked amount.

Updates

Lead Judging Commences

0kage Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.