<!-- canonical: https://0xsimao.com/findings/benddao-collected-fines-yield-staking -->

# It's impossible to retrieve collected fines from the yield staking contract

Medium · Code4rena · NFT lending · 19th June, 2024

Finding M-15 of the BendDAO security review.

- Protocol: https://www.benddao.xyz/
- Report: /reports/benddao
- Codebase: https://github.com/0xsimao/2024-07-benddao/tree/117ef61967d4b318fc65170061c9577e674fffa1
- Source: https://code4rena.com/reports/2024-07-benddao

---

[https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L329-L337](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L329-L337)

[https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L407](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L407)

[https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L426](https://github.com/code-423n4/2024-07-benddao/blob/main/src/yield/YieldStakingBase.sol#L426)

### Impact

No means to retrieve collected fines from the staking contract.

### Proof of Concept

If `botAdmin` forcefully unstakes a position, a staker will have to pay an additional fine when the stake is repayed:

```
  function _repay(uint32 poolId, address nft, uint256 tokenId) internal virtual {
    ---SNIP---

    vars.nftDebt = _getNftDebtInUnderlyingAsset(sd);
>>  vars.nftDebtWithFine = vars.nftDebt + sd.unstakeFine;

    // compute repay value
    if (vars.claimedYield >= vars.nftDebtWithFine) {
      vars.remainAmount = vars.claimedYield - vars.nftDebtWithFine;
    } else {
      vars.extraAmount = vars.nftDebtWithFine - vars.claimedYield;
    }

    // transfer eth from sender
    if (vars.extraAmount > 0) {
>>    underlyingAsset.safeTransferFrom(vars.nftOwner, address(this), vars.extraAmount);
    }

    if (vars.remainAmount > 0) {
      underlyingAsset.safeTransfer(vars.nftOwner, vars.remainAmount);
    }

    // repay lending pool
>>  poolYield.yieldRepayERC20(poolId, address(underlyingAsset), vars.nftDebt);

    poolYield.yieldSetERC721TokenData(poolId, nft, tokenId, false, address(underlyingAsset));

    // update shares
    accountYieldInWithdraws[address(vars.yieldAccout)] -= sd.withdrawAmount;
    totalDebtShare -= sd.debtShare;

    delete stakeDatas[nft][tokenId];

    emit Repay(msg.sender, nft, tokenId, vars.nftDebt);
  }
```

Note that the user's total debt consists of the actual NFT debt and the fine. When the stake is paid off, only the `nftDebt` is sent to the pool, and the `unstakeFine` remains in the contract. However, there are no functions that send the collected funds to the admin, and so they will remain in the contract forever.

### Recommended Mitigation Steps

Implement a function that allows admin to collect fines from the yield staking contract.

### Assessed type

Token-Transfer

---

Related findings:

- [StakingOperator::_setUnlockWindow() checks if the times are negative, which is impossible](https://0xsimao.com/findings/singularity-staking-window-times-negative): Singularity
