HIGH severity: `AccountableFixedTerm::claimInterest` unpredictable due to share burn mechanics. **Description:** [`AccountableFixedTerm::claimInterest`](https://github.com/Accountable-Protocol/audit-2025-09-accountable/blob/fc43546fe67183235c0725f6214ee2b876b1aac6/src/strategies/AccountableFixedTerm.sol#L215-L217) lets a lender redeem their share of already-paid interest by burning vault...

Vulnerable code:
uint256 maxNetYield = PRECISION + _interestParams.netReturn;
claimedInterest = shares.mulDiv(claimableInterest, totalShares, Math.Rounding.Floor);
uint256 usedShares = claimedInterest.mulDiv(PRECISION, maxNetYield, Math.Rounding.Ceil);

function test_earlyClaimerAdvantage_dueToMaxNetReturnBurn_usdc() public {
    vm.warp(1739893670);

    // Setup borrower/terms identical to other tests
    vm.prank(manager);
    usdcLoan.setPendingBorrower(borrower);

    vm.prank(borrower);
    usdcLoan.acceptBorrowerRole();

    vm.prank(manager);
    usdcLoan.setTerms(
        LoanTerms({
            minDeposit: 0,
            minRedeem: 0,
            maxCapacity: USDC_AMOUNT,
            minCapacity: USDC_AMOUNT / 2,
            interestRate: 1e5,
            interestInterval: 30 days,
            duration: 360 days,
            lateInterestGracePeriod: 2 days,
            depositPeriod: 2 days,
            acceptGracePeriod: 0,
            lateInterestPenalty: 5e2,
            withdrawalPeriod: 0
        })
    );

    // Equal deposits for Alice & Bob
    uint256 userDeposit = USDC_AMOUNT / 2;

    uint256 aliceBalanceBefore = usdc.balanceOf(alice);
    uint256 bobBalanceBefore   = usdc.balanceOf(bob);

    vm.prank(alice);
    usdcVault.deposit(userDeposit, alice, alice);

    vm.prank(bob);
    usdcVault.deposit(userDeposit, bob, bob);

    // Sanity: equal initial shares
    assertEq(usdcVault.balanceOf(alice), userDeposit, "alice initial shares");
    assertEq(usdcVault.balanceOf(bob),   userDeposit, "bob initial shares");

    // Accept loan
    vm.warp(block.timestamp + 3 days);
    vm.prank(borrower);
    usdcLoan.acceptLoanLocked();

    // Fund borrower to pay interest and approve
    usdc.mint(borrower, 2_000_000e6);
    vm.prank(borrower);
    usdc.approve(address(usdcLoan), 2_000_000e6);

    uint256 aliceMidClaim;
    uint256 aliceEndClaim;
    uint256 bobEndClaim;

    // Pay month by month; Alice claims once in the middle, Bob waits
    for (uint8 i = 1; i <= 12; i++) {
        uint256 nextDueDate = usdcLoan.loan().startTime + (i * usdcLoan.loan().interestInterval);
        vm.warp(nextDueDate + 1 days);

        // Borrower pays owed interest for this interval
        vm.startPrank(borrower);
        uint256 owed = _interestOwed(usdcLoan);
        usdcLoan.pay(owed);
        vm.stopPrank();

        // Alice claims right after month 6 payment
        if (i == 6) {
            vm.prank(alice);
            aliceMidClaim = usdcLoan.claimInterest();
            assertGt(aliceMidClaim, 0, "alice mid-term claim > 0");
        }
    }

    // After last payment, both can claim
    vm.prank(alice);
    aliceEndClaim += usdcLoan.claimInterest();

    vm.prank(bob);
    bobEndClaim += usdcLoan.claimInterest();

    uint256 aliceTotal = aliceMidClaim + aliceEndClaim;
    uint256 bobTotal   = bobEndClaim;

    // Alice has gotten more than Bob by claiming early
    assertGt(aliceTotal, bobTotal, "Alice (mid+end) should claim more than Bob (end only)");

    // repay & clean-up
    vm.prank(borrower);
    usdcLoan.repay(0);

    // Ensure both still redeem principal back pro-rata after interest claims
    uint256 sharesAlice = usdcVault.balanceOf(alice);
    uint256 sharesBob   = usdcVault.balanceOf(bob);

    vm.prank(alice);
    usdcVault.requestRedeem(sharesAlice, alice, alice);
    vm.prank(bob);
    usdcVault.requestRedeem(sharesBob, bob, bob);

    vm.startPrank(alice);
    uint256 maxWithdrawAlice = usdcVault.maxWithdraw(alice);
    usdcVault.withdraw(maxWithdrawAlice, alice, alice);
    vm.stopPrank();

    vm.startPrank(bob);
    uint256 maxWithdrawBob = usdcVault.maxWithdraw(bob);
    usdcVault.withdraw(maxWithdrawBob, bob, bob);
    vm.stopPrank();

    assertEq(usdcVault.balanceOf(alice), 0, "alice no shares");
    assertEq(usdcVault.balanceOf(bob),   0, "bob no shares");

    uint256 aliceBalanceAfter  = usdc.balanceOf(alice);
    uint256 bobBalanceAfter    = usdc.balanceOf(bob);

    uint256 aliceGain = aliceBalanceAfter - aliceBalanceBefore;
    uint256 bobGain   = bobBalanceAfter   - bobBalanceBefore;

    // Alice and Bob has gained the same in the end
    assertEq(aliceGain, bobGain, "alice and bob gained the same");
}

uint256 accInterestPerShare;
mapping(address user => uint256 index) userIndex;
mapping(address user => uint256 interest) pendingInterest;

function onTransfer(address from, address to, uint256 amount) external onlyVault nonReentrant {

    // Settle sender’s pending interest (if not mint)
    if (from != address(0)) {
        _settleAccount(from);
        userIndex[from] = accInterestPerShare;
    }

    // Settle receiver’s pending interest (if not burn)
    if (to != address(0)) {
        _settleAccount(to);
        userIndex[to] = accInterestPerShare;
    }

}

/// Internal: settle one account’s pending interest using current accumulator
function _settleAccount(address user) internal {
    uint256 shares = vault.balanceOf(user);
    uint256 idx = userIndex[user];

    if (shares == 0) {
        userIndex[user] = accInterestPerShare;
        return;
    }

    uint256 delta  = accInterestPerShare - idx;
    if (delta == 0) return;

    pendingInterest[user] += (shares * delta) / PRECISION;
    userIndex[user] = accInterestPerShare;
}