# _handleRepay of MoneyMarketHook does not consider the actual debt shares of the posId inside the position manager and could lead to a user's tokens getting stuck inside the hook

MoneyMarketHook computes repay amount from user-supplied shares, not actual posId debt, so over-repayment after liquidation leaves tokens stuck in the hook.

- Payout: Contest reward
- Severity: high
- Program: INIT Capital
- Credited: said
- Disclosed: 2024-01-16
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-12-initcapital-findings/issues/28
- Library page: https://bugbountylibrary.com/r/c4%3A2023-12-initcapital%3AH-03
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:race-window technique:source-review vuln:accounting-error vuln:business-logic

**Target:** MoneyMarketHook._handleRepay / InitCore repay
**Root cause:** _handleRepay converts user-supplied _params[i].shares to repayAmt and pulls that amount from the user, but InitCore._repay caps sharesToRepay at the position's actual debt shares, so the pulled amount can exceed what is consumed.
**Steps:**
1. User calls MoneyMarketHook with repayParams[i].shares equal to full position debt.
2. _handleRepay computes `repayAmt = debtShareToAmtCurrent(_params[i].shares)` and `safeTransferFrom(msg.sender, address(this), repayAmt)`.
3. Liquidator front-runs and liquidates the position, reducing posId debt shares.
4. InitCore._repay reads `positionDebtShares = getPosDebtShares(_posId,_pool)` and uses `sharesToRepay = min(_shares, positionDebtShares)`, transferring only the smaller amtToRepay to the pool.
5. Excess tokens remain in MoneyMarketHook with no path to return them to the user.
**How found:** Code reading of _handleRepay showed it derives repayAmt solely from user-supplied shares, then comparing with InitCore._repay revealed the min() cap against actual position debt shares, exposing the mismatch.
**Exploitation:** Front-run a user's repay transaction with a liquidation of the same posId so the hook has already pulled more underlying tokens than InitCore will consume; the surplus is stranded in the hook contract.
**Insight:** When a wrapper contract pre-computes and pulls token amounts before calling a core function, check whether the core function independently clamps the amount (min with actual state); any pre-pull based on user input can over-transfer and strand funds.
