Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: medium
Invalid

VaultDepositController::_depositToVaults Fails to Update Total Deposits and Principal Deposits Correctly

Summary

The _depositToVaults function in VaultControllerStrategy.sol does not correctly update the total deposits and principal deposits, leading to incorrect state variables and potential inconsistencies in the contract's behavior.

Vulnerability Details

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/linkStaking/base/VaultControllerStrategy.sol#L172C1-L292C6

The _depositToVaults function is responsible for depositing tokens into various vaults according to specified limits and conditions. However, the function does not correctly update the state variables totalPrincipalDeposits and totalDeposits, resulting in incorrect balances and deposits being reported. This discrepancy can lead to incorrect calculations and decisions based on the contract's state.

The root cause of the issue appears to be that the _depositToVaults function does not properly update the state variables after performing deposit operations. This can be due to variable shadowing or incorrect logic within the function that prevents the state from being updated correctly.

POC

  • Copy the test to the existing test file test/linkStaking/vault-controller-strategy.test.ts

it('should handle deposit limits correctly in _depositToVaults', async () => {
const { adrs, strategy, token, stakingController, vaults } = await loadFixture(deployFixture);
// Set up initial conditions
await token.transfer(adrs.strategy, toEther(1000));
await strategy.deposit(toEther(500), encodeVaults([]));
// Log initial balances and deposits
console.log('Initial balance of stakingController:', fromEther(await token.balanceOf(adrs.stakingController)));
console.log('Initial totalPrincipalDeposits:', fromEther(await strategy.totalPrincipalDeposits()));
console.log('Initial totalDeposits:', fromEther(await strategy.getTotalDeposits()));
// Set deposit limits
const minDepositLimit = toEther(10);
const maxDepositLimit = toEther(120);
await stakingController.setDepositLimits(minDepositLimit, maxDepositLimit);
// Log deposit limits
console.log('Deposit limits set: minDepositLimit =', fromEther(minDepositLimit), ', maxDepositLimit =', fromEther(maxDepositLimit));
// Attempt to deposit an amount below the minimum limit
try {
await strategy.deposit(toEther(5), encodeVaults([]));
} catch (error) {
if (error instanceof Error) {
console.log('Error when depositing below minimum limit:', error.message);
} else {
console.log('Unknown error when depositing below minimum limit:', error);
}
}
// Attempt to deposit an amount above the maximum limit
try {
await strategy.deposit(toEther(200), encodeVaults([]));
} catch (error) {
if (error instanceof Error) {
console.log('Error when depositing above maximum limit:', error.message);
} else {
console.log('Unknown error when depositing above maximum limit:', error);
}
}
// Deposit an amount within the limits
await strategy.deposit(toEther(50), encodeVaults([]));
console.log('Balance of stakingController after deposit within limits:', fromEther(await token.balanceOf(adrs.stakingController)));
console.log('TotalPrincipalDeposits after deposit within limits:', fromEther(await strategy.totalPrincipalDeposits()));
console.log('TotalDeposits after deposit within limits:', fromEther(await strategy.getTotalDeposits()));
// Manipulate the deposit limits and test again
await stakingController.setDepositLimits(toEther(20), toEther(100));
console.log('New deposit limits set: minDepositLimit =', fromEther(toEther(20)), ', maxDepositLimit =', fromEther(toEther(100)));
// Attempt to deposit an amount below the new minimum limit
try {
await strategy.deposit(toEther(15), encodeVaults([]));
} catch (error) {
if (error instanceof Error) {
console.log('Error when depositing below new minimum limit:', error.message);
} else {
console.log('Unknown error when depositing below new minimum limit:', error);
}
}
// Attempt to deposit an amount above the new maximum limit
try {
await strategy.deposit(toEther(150), encodeVaults([]));
} catch (error) {
if (error instanceof Error) {
console.log('Error when depositing above new maximum limit:', error.message);
} else {
console.log('Unknown error when depositing above new maximum limit:', error);
}
}
// Deposit an amount within the new limits
await strategy.deposit(toEther(80), encodeVaults([]));
console.log('Balance of stakingController after deposit within new limits:', fromEther(await token.balanceOf(adrs.stakingController)));
console.log('TotalPrincipalDeposits after deposit within new limits:', fromEther(await strategy.totalPrincipalDeposits()));
console.log('TotalDeposits after deposit within new limits:', fromEther(await strategy.getTotalDeposits()));
// Assertions
assert.equal(
fromEther(await token.balanceOf(adrs.stakingController)),
370,
'Total deposits should be updated correctly'
);
assert.equal(
fromEther(await strategy.totalPrincipalDeposits()),
630,
'Total principal deposits should be updated correctly'
);
assert.equal(
fromEther(await strategy.getTotalDeposits()),
630,
'Total deposits should be updated correctly'
);
});
  • Output:

1) VaultControllerStrategy
should handle deposit limits correctly in _depositToVaults:
Total deposits should be updated correctly
+ expected - actual
-1500
+370

The test case demonstrates that the initial balance and deposits remain unchanged after the deposit operations, indicating that the _depositToVaults function is not updating the state variables correctly. The expected total deposits should be 370 (1000 - 630), but the actual value remains 1500, showing that the deposits were not processed correctly.

Impact

The incorrect state updates can lead to inconsistencies in the contract's behavior, potentially affecting the accuracy of the reported balances and deposits. This can result in incorrect calculations and decisions based on the contract's state. Users may be misled by the incorrect balances, leading to potential financial losses or incorrect strategic decisions.

Tools Used

  • Hardhat

Recommendations

  • Review and Fix the _depositToVaults Function: Ensure that the function correctly updates the state variables totalPrincipalDeposits and totalDeposits after each deposit operation. Verify that there is no variable shadowing or incorrect logic that prevents the state from being updated correctly.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 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.