Liquid Staking

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

cannot be able to withdraw tokens when strategy wrongly set

Summary

The documentation states that users can withdraw their LINK from the Priority Pool at any time. However, when the strategy is incorrectly set with minDeposits equal to maxDeposits, users are unable to withdraw tokens. In the deployed contracts, the situation where minDeposits equals maxDeposits is intentionally set.

Vulnerability Details

The documentation confirms that users have the ability to withdraw their LINK from the Priority Pool whenever they choose.(FAQ | stake.link

5. Can I withdraw my LINK from the Priority Pool?
Yes, you can withdraw your LINK from the Priority Pool at any time.

Additionally, in the deployed contracts, the condition where minDeposits is equal to maxDeposits is deliberately established. This is evident as getMaxDeposits() is equivalent to getMinDeposits().

Deployed Contracts | stake.link

strategy one contract

getMaxDeposits() = 1533884834393893637465945

getMinDeposits() = 1533884834393893637465945

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/base/Strategy.sol#L51

In this case, the user is unable to withdraw their LINK from the Priority Pool.

Proof of Concept

it('cannot be able to withdraw tokens', async () => {
const { signers, accounts } = await getAccounts()
const adrs: any = {}
const token = (await deploy('contracts/core/tokens/base/ERC677.sol:ERC677', [
'Chainlink',
'LINK',
1000000000,
])) as ERC677
adrs.token = await token.getAddress()
await setupToken(token, accounts)
const erc677Receiver = (await deploy('ERC677ReceiverMock')) as ERC677ReceiverMock
adrs.erc677Receiver = await erc677Receiver.getAddress()
const stakingPool = (await deployUpgradeable('StakingPool', [
adrs.token,
'LinkPool LINK',
'lpLINK',
[
[accounts[4], 1000],
[adrs.erc677Receiver, 2000],
],
toEther(10000),
])) as StakingPool
adrs.stakingPool = await stakingPool.getAddress()
const strategy1 = (await deployUpgradeable('StrategyMock', [
adrs.token,
adrs.stakingPool,
toEther(100),
toEther(100), // when maxDeposits == minDeposits
])) as StrategyMock
adrs.strategy1 = await strategy1.getAddress()
await stakingPool.addStrategy(adrs.strategy1)
await stakingPool.setPriorityPool(accounts[0])
await stakingPool.setRebaseController(accounts[0])
await token.approve(adrs.stakingPool, ethers.MaxUint256)
//--------------------------------------------------------------------------------
let balanceBefore = await token.balanceOf(accounts[1])
await token.connect(signers[1]).transfer(accounts[0], toEther(100))
await stakingPool.deposit(accounts[1], toEther(100), ['0x'])
// can't withdraw more than 0
let canWithdraw = await strategy1.canWithdraw()
assert.equal(fromEther(canWithdraw), 0, "can withdraw 0")
// Error: VM Exception while processing transaction: reverted with reason string 'Not enough liquidity available to withdraw'
// await stakingPool.withdraw(accounts[1], accounts[1], toEther(100), ['0x'])
await stakingPool.withdraw(accounts[1], accounts[1], toEther(0), ['0x'])
let balanceAfter = await token.balanceOf(accounts[1])
assert.equal(balanceBefore - balanceAfter, toEther(100), "user lost tokens")
})

Impact

Users are unable to withdraw their LINK from the Priority Pool and lose funds.

Tools Used

Manual code review

Recommendations

When deploying the strategy contract, make sure that minDeposits is not equal to maxDeposits.

Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

[INVALID] Improper strategy deployment

Support

FAQs

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