Assessment reports>StakeKit>Threat Model>withdraw

Function: withdraw(uint256 _underlying, address receiver, address owner)

This function designates the assets to be withdrawn using the _underlying value, facilitating the withdrawal of assets from the ERC-4626 vault.

Inputs

  • _underlying

    • Control: Arbitrary.

    • Constraints: It must be greater than zero and less than or equal to the balance of maxWithdraw(owner).

    • Impact: Specifies the amount of assets to be received.

  • receiver

    • Control: Arbitrary.

    • Constraints: A value of type address.

    • Impact: It is the address of the wallet receiving the assets.

  • owner

    • Control: Arbitrary.

    • Constraints: A value of type address.

    • Impact: Used only for validating the _underlying value.

Branches and code coverage

Intended branches

  • A normal withdrawal occurs when _underlying greater than zero and less than or equal to the maxWithdraw(owner) is provided.

Negative behavior

  • The transaction reverts when the _underlying value is zero.

  • The transaction reverts when the _underlying value is less than maxWithdraw(0).

Function call analysis

  • this.maxWithdraw(owner) -> this.previewRedeem(shares) -> this.previewHarvest() -> this.computeHarvestFee() -> this.strategy.convertToAssets(this.totalAssets())

    • What is controllable? The owner value.

    • If the return value is controllable, how is it used and how can it go wrong? The range of the _underlying value can be extended.

    • What happens if it reverts, reenters or does other unusual control flow? No impact.

  • this.strategy.convertToShares(_underlying)

    • What is controllable? The _underlying value.

    • If the return value is controllable, how is it used and how can it go wrong? The amount of assets received can be maliciously manipulated.

    • What happens if it reverts, reenters or does other unusual control flow? If reentrancy is possible, it may lead to an increase in the totalSupply() value through repetitive calls to the harvest function, potentially resulting in the permanent freezing of funds.

  • SafeERC20.safeTransfer(IERC20(address(this.strategy)), receiver, assets)

    • What is controllable? The assets value and receiver value.

    • If the return value is controllable, how is it used and how can it go wrong? No impact.

    • What happens if it reverts, reenters or does other unusual control flow? While a reentrancy scenario is possible, it may not provide sufficient incentive for an attack, as shares are burned in advance.

  • this.strategy.withdraw(_underlying, receiver, address(this))

    • What is controllable? The _underlying value and receiver value.

    • If the return value is controllable, how is it used and how can it go wrong? No impact.

    • What happens if it reverts, reenters or does other unusual control flow? While a reentrancy scenario is possible, it may not provide sufficient incentive for an attack, as shares are burned in advance.

  • this.strategy.convertToAssets(this.totalAssets())

    • What is controllable? It is uncontrollable.

    • If the return value is controllable, how is it used and how can it go wrong? The fee process can be maliciously manipulated.

    • What happens if it reverts, reenters or does other unusual control flow? While a reentrancy scenario is possible, it may not provide sufficient incentive for an attack, as shares are burned in advance.

Zellic © 2025Back to top ↑