# User's attempt to deposit & withdraw reverts due to the calculation style inside _calculateShares()

Off-by-one rounding in _calculateShares desyncs totalDepositShares from pseudoTotalPool, making share price exceed max and reverting deposits/withdrawals.

- Payout: Contest reward
- Severity: medium
- Program: Wise Lending
- Credited: t0x1c
- Disclosed: 2024-05-03
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-02-wise-lending-findings/issues/27
- Library page: https://bugbountylibrary.com/r/c4%3A2024-02-wise-lending%3AM-17
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:dos vuln:precision-loss

**Target:** WiseLending depositExactAmountETH / withdrawExactAmountETH share accounting
**Root cause:** _calculateShares subtracts 1 from computed shares (rounding in protocol's favor) but pseudoTotalPool is never adjusted, so totalDepositShares and pseudoTotalPool diverge; _getSharePrice then returns a value above currentSharePriceMax, failing _validateParameter in _compareSharePrices.
**Steps:**
1. Alice calls `depositExactAmountETH{value: 1 ether}(nftId)` — succeeds.
2. Bob calls `depositExactAmountETH{value: 1.5 ether}(nftId_bob)` — reverts.
3. Trace: syncPool modifier runs _syncPoolAfterCodeExecution -> _compareSharePrices.
4. During deposit, _handleDeposit -> calculateLendingShares -> _calculateShares returns `_product/_pseudo - 1`, lowering totalDepositShares.
5. _getSharePrice computes `pseudoTotalPool*1e18/totalDepositShares` = 1000000000000000001 > currentSharePriceMax 1e18.
6. _validateParameter(lendSharePriceAfter, currentSharePriceMax) reverts.
7. Withdraw variant: deposit 10 ether then `withdrawExactAmountETH(nftId, 9.1 ether)` reverts; only <=9 ether succeeds.
**How found:** Code reading of the syncPool modifier and share math: noticed _calculateShares rounds down by 1 while pseudoTotalPool is untouched, hypothesized divergence would push computed share price above the max check, confirmed with Foundry fork tests.
**Exploitation:** No direct theft; griefing/DoS. A borrower attempting to add collateral to avoid liquidation has the deposit revert, potentially getting liquidated; a depositor cannot withdraw their full balance in one tx.
**Insight:** When a protocol rounds shares down in its own favor, check whether the paired accounting variable (pseudoTotalPool) is adjusted in lockstep; a one-sided -1 creates a slow drift that eventually trips invariant checks like share-price-max validation.
