Changes in `dittoShorterRate` affect retroactively to accrued Ditto yield shares
The calculation of the Ditto rewards earned by shorters does not take into account that the changes in the Ditto shorter rate will impact retroactively, inflating or deflating the new Ditto rewards of the users.\\n`YieldFacet.sol:distributeYield()` calculates and credits ZETH and Ditto rewards earned from short records by `msg.sender`. The distribution of the rewards is performed in the `_claimYield()` function:\\n```\\n125     // Credit ZETH and Ditto rewards earned from shortRecords from all markets\\n126     function _claimYield(uint256 vault, uint88 yield, uint256 dittoYieldShares) private {\\n127         STypes.Vault storage Vault = s.vault[vault];\\n128         STypes.VaultUser storage VaultUser = s.vaultUser[vault][msg.sender];\\n129         // Implicitly checks for a valid vault\\n130         if (yield <= 1) revert Errors.NoYield();\\n131         // Credit yield to ethEscrowed\\n132         VaultUser.ethEscrowed += yield;\\n133         // Ditto rewards earned for all shorters since inception\\n134         uint256 protocolTime = LibOrders.getOffsetTime();\\n135         uint256 dittoRewardShortersTotal = Vault.dittoShorterRate * protocolTime;\\n136         // Ditto reward proportion from this yield distribution\\n137         uint256 dittoYieldSharesTotal = Vault.zethCollateralReward;\\n138         uint256 dittoReward =\\n139             dittoYieldShares.mul(dittoRewardShortersTotal).div(dittoYieldSharesTotal);\\n140         // Credit ditto reward to user\\n141         if (dittoReward > type(uint80).max) revert Errors.InvalidAmount();\\n142         VaultUser.dittoReward += uint80(dittoReward);\\n143     }\\n```\\n\\nFocusing on the Ditto rewards, we can see that the function receives the number of yield shares earned by the user (dittoYieldShares) and in line 138 calculates the Ditto reward by multiplying this amount by the total amount of rewards of the protocol (dittoRewardShortersTotal) and dividing it by the total amount of yield shares of the protocol (dittoYieldSharesTotal).\\nIf we take a look in line 135 at how the `dittoRewardShortersTotal` is calculated, we can see that it is the product of the Ditto shorter rate and total time elapsed since the protocol deployment.\\nThis last calculation is wrong, as it is assumed that the Ditto shorter rate is constant, but this parameter can be changed by the admin or the DAO. This means that the changes in the Ditto shorter rate will impact retroactively, inflating or deflating the new Ditto rewards of the users. Also, users that have yielded the same number of shares during the same period, will receive different rewards depending on whether they claim their rewards before or after the Ditto shorter rate change.\\nAdd the following code snippet into `test/Yield.t.sol` and run `forge test --mt testYieldRateChange`.\\n```\\n    function testYieldRateChange() public {\\n        address alice = makeAddr("alice");\\n        address bob = makeAddr("bob");\\n        address[] memory assets = new address[](1);\\n        assets[0] = asset;\\n\\n        fundLimitBid(DEFAULT_PRICE, 320000 ether, receiver);\\n        fundLimitShort(DEFAULT_PRICE, 80000 ether, alice);\\n        fundLimitShort(DEFAULT_PRICE, 80000 ether, bob);\\n        generateYield();\\n        skip(yieldEligibleTime);\\n\\n        // Alice and Bob have the same number of Ditto yield shares\\n        assertEq(diamond.getDittoMatchedReward(vault, alice), diamond.getDittoMatchedReward(vault, alice));\\n\\n        // Alice's yield is distributed\\n        vm.prank(alice);\\n        diamond.distributeYield(assets);\\n\\n        // Ditto shorter rate is updated\\n        vm.prank(owner);\\n        diamond.setDittoShorterRate(vault, 2);\\n\\n        // Bob's yield is distributed\\n        vm.prank(bob);\\n        diamond.distributeYield(assets);\\n\\n        uint256 aliceDittoRewards = diamond.getDittoReward(vault, alice);\\n        uint256 bobDittoRewards = diamond.getDittoReward(vault, bob);\\n\\n        // Bob receives more Ditto rewards than Alice, even both were entitled to the same amount\\n        assertApproxEqAbs(aliceDittoRewards * 2, bobDittoRewards, 2);\\n    }\\n```\\n
Create two new state variables that keep track of the timestamp of the last Ditto shorter rate update and the total Ditto rewards accrued at that time. Then the calculation of `dittoRewardShortersTotal` would be:\\n```\\n    uint256 dittoRewardShortersTotal = lastSnapshotRewards + Vault.dittoShorterRate * (protocolTime - lastSnapshotTimestamp);\\n```\\n
Changes in the Ditto shorter rate will impact retroactively, inflating or deflating the new Ditto rewards of the users. Users might not be incentivized to claim their rewards, as they might receive more rewards if they wait for the Ditto shorter rate to change.
```\\n125     // Credit ZETH and Ditto rewards earned from shortRecords from all markets\\n126     function _claimYield(uint256 vault, uint88 yield, uint256 dittoYieldShares) private {\\n127         STypes.Vault storage Vault = s.vault[vault];\\n128         STypes.VaultUser storage VaultUser = s.vaultUser[vault][msg.sender];\\n129         // Implicitly checks for a valid vault\\n130         if (yield <= 1) revert Errors.NoYield();\\n131         // Credit yield to ethEscrowed\\n132         VaultUser.ethEscrowed += yield;\\n133         // Ditto rewards earned for all shorters since inception\\n134         uint256 protocolTime = LibOrders.getOffsetTime();\\n135         uint256 dittoRewardShortersTotal = Vault.dittoShorterRate * protocolTime;\\n136         // Ditto reward proportion from this yield distribution\\n137         uint256 dittoYieldSharesTotal = Vault.zethCollateralReward;\\n138         uint256 dittoReward =\\n139             dittoYieldShares.mul(dittoRewardShortersTotal).div(dittoYieldSharesTotal);\\n140         // Credit ditto reward to user\\n141         if (dittoReward > type(uint80).max) revert Errors.InvalidAmount();\\n142         VaultUser.dittoReward += uint80(dittoReward);\\n143     }\\n```\\n