Liquid Staking

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

Incorrect Principal Adjustment in performUpkeep Leads to Fund Loss and Unfair Reward Distribution

Details

The LSTRewardsSplitter contract's performUpkeep function is responsible for distributing earned rewards. It calculates the rewards as the difference between the current LST balance and the recorded principalDeposits.

The function has a flaw in its logic for handling cases where the current LST balance is less than principalDeposits. Instead of reverting the transaction, it attempts to adjust principalDeposits downwards. This adjustment is incorrect and could lead to an inconsistent state where principalDeposits no longer accurately reflects the actual principal deposited by users.

Code Snippet

function performUpkeep(bytes calldata) external {
int256 newRewards = int256(lst.balanceOf(address(this))) - int256(principalDeposits);
if (newRewards < 0) {
principalDeposits -= uint256(-1 * newRewards); // Incorrect adjustment of principalDeposits
}
// ... (rest of the function) ...
}

Impact

  • Inconsistent State: The incorrect adjustment of principalDeposits can lead to a mismatch between the contract's internal accounting and the actual principal.

  • Incorrect Reward Distribution: Future reward calculations will be based on the incorrectly adjusted principalDeposits, potentially leading to overstated rewards and an unfair distribution.

  • Loss of Funds: In the long run, this inconsistency could result in a situation where users might not be able to withdraw their full deposit, as the contract's record of their principal is lower than the actual amount.

Scenario

  • A user deposits 100 LST tokens.

  • Due to an external factor (e.g., a vulnerability in the LST token or slashing), 50 tokens are lost from the contract.

  • The contract now has 50 tokens, but principalDeposits is still 100.

  • When performUpkeep is called, instead of reverting, it adjusts principalDeposits to 50.

  • Future reward calculations will be based on this lower principal, potentially leading to the distribution of user funds as "rewards."

Fix

Revert the transaction when the current balance is less than principalDeposits. This ensures that the contract maintains an accurate record of the principal and prevents incorrect reward distribution.

function performUpkeep(bytes calldata) external {
uint256 currentBalance = lst.balanceOf(address(this));
require(currentBalance >= principalDeposits, "InsufficientBalance()"); // Revert if balance is less than principalDeposits
// ... (rest of the function) ...
}

Poc

it('performUpkeep should revert with insufficient balance', async () => {
const { accounts, controller, token, splitter0 } = await loadFixture(deployFixture);
await token.transferAndCall(controller.target, toEther(100), '0x'); // Deposit 100 tokens
// Simulate a loss of tokens (e.g., through a vulnerability in the LST token)
await token.burn(splitter0.target, toEther(50));
// Attempt to call performUpkeep
await expect(
controller.performUpkeep(ethers.AbiCoder.defaultAbiCoder().encode(['bool[]'], [[true, false]]))
).to.be.revertedWithCustomError(splitter0, 'InsufficientBalance()'); // Or a similar custom error
// Assert that principalDeposits remains unchanged
assert.equal(fromEther(await splitter0.principalDeposits()), 100, 'principalDeposits should not be adjusted');
});
Updates

Lead Judging Commences

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.