# `JUSDBankStorage::getTRate()`,`JUSDBankStorage::accrueRate()` are calculated differently, and the data calculation is biased, Causes the `JUSDBank` contract funciton result to be incorrect

getTRate() and accrueRate() compute interest differently (linear vs compounding), so view-based safety checks and flashLoan diverge from stored tRate, biasing account-safety results.

- Payout: Contest reward
- Severity: medium
- Program: Jojo Exchange Update
- Credited: FastTiger
- Disclosed: 2023-12-14
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-12-jojo-exchange-update-judging/issues/1
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-12-jojo-exchange-update%3AM-1
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:accounting-error

**Target:** JUSDBankStorage interest rate accrual (Solidity)
**Root cause:** accrueRate() compounds via decimalMul((timeDiff*borrowFeeRate)/SECONDS_PER_YEAR + 1e18) while getTRate() adds a simple linear term tRate + (borrowFeeRate*timeDiff)/SECONDS_PER_YEAR, so the view and stored rate diverge.
**Steps:**
1. Deploy JUSDBank and note lastUpdateTimestamp.
2. vm.warp(block.timestamp + 18_356 days); call accrueRate() so tRate > 2e18.
3. vm.warp(+1 second); compare getTRate() vs accrueRate() result — deviation appears.
4. Repeat with +1 day warp; deviation grows with elapsed time and tRate magnitude.
**How found:** Code reading of the two rate functions revealed inconsistent formulas (linear vs compounding), then a Foundry test warped time to quantify the deviation.
**Insight:** When a protocol exposes both a view and a state-mutating accrual of the same interest index, diff the two formulas — view paths used in safety checks (isAccountSafe, flashLoan) can silently diverge from stored state and misprice risk.
