Not properly tracking debt accrual leads mintOpenInterestDebt() to lose twTap rewards
Debt accrual is tracked wrongly, making the expected twTap rewards to be potentially lost.\\nPenrose's `mintOpenInterestDebt()` function allows USDO to be minted and distributed as a reward to twTap holders based on the current USDO open interest.\\nIn order to mint and distribute rewards, `mintOpenInterestDebt()` will perform the following steps:\\nQuery the current `USDO.supply()`\\nCompute the total debt from all the markets (Origins included)\\nIf `totalUsdoDebt > usdoSupply`, then distribute the difference among the twTap holders\\n```\\nfunction mintOpenInterestDebt(address twTap) external onlyOwner { \\n        uint256 usdoSupply = usdoToken.totalSupply();\\n\\n        // nothing to mint when there's no activity\\n        if (usdoSupply > 0) {  \\n            // re-compute latest debt\\n            uint256 totalUsdoDebt = computeTotalDebt();  \\n   \\n            //add Origins debt \\n            //Origins market doesn't accrue in time but increases totalSupply\\n            //and needs to be taken into account here\\n            uint256 len = allOriginsMarkets.length;\\n            for (uint256 i; i < len; i++) {\\n                IMarket market = IMarket(allOriginsMarkets[i]);\\n                if (isOriginRegistered[address(market)]) {\\n                    (uint256 elastic,) = market.totalBorrow();\\n                    totalUsdoDebt += elastic;\\n                }\\n            }\\n \\n            //debt should always be > USDO supply\\n            if (totalUsdoDebt > usdoSupply) { \\n                uint256 _amount = totalUsdoDebt - usdoSupply;\\n\\n                //mint against the open interest; supply should be fully minted now\\n                IUsdo(address(usdoToken)).mint(address(this), _amount);\\n\\n                //send it to twTap\\n                uint256 rewardTokenId = ITwTap(twTap).rewardTokenIndex(address(usdoToken));\\n                _distributeOnTwTap(_amount, rewardTokenId, address(usdoToken), ITwTap(twTap));\\n            }\\n        } \\n    }\\n```\\n\\nThis approach has two main issues that make the current reward distribution malfunction:\\nBecause debt is not actually tracked and is instead directly queried from the current total borrows via `computeTotalDebt()`, if users repay their debt prior to a reward distribution this debt won't be considered for the fees, given that fees will always be calculated considering the current `totalUsdoDebt` and `usdoSupply`.\\nBridging USDO is not considered\\nIf USDO is bridged from another chain to the current chain, then the `usdoToken.totalSupply()` will increment but the `totalUsdoDebt()` won't. This will make rewards never be distributed because `usdoSupply` will always be greater than `totalUsdoDebt`.\\nOn the other hand, if USDO is bridged from the current chain to another chain, the `usdoToken.totalSupply()` will decrement and tokens will be burnt, while `totalUsdoDebt()` will remain the same. This will make more rewards than the expected ones to be distributed because `usdoSupply` will be way smaller than `totalUsdoDebt`.\\nConsider the following scenario: 1000 USDO are borrowed, and already 50 USDO have been accrued as debt.\\nThis makes USDO's totalSupply() to be 1000, while `totalUsdoDebt` be 1050 USDO. If `mintOpenInterestDebt()` is called, 50 USDO should be minted and distributed among twTap holders.\\nHowever, prior to executing `mintOpenInterestDebt()`, a user bridges 100 USDO from chain B, making the total supply increment from 1000 USDO to 1100 USDO. Now, totalSupply() is 1100 USDO, while `totalUsdoDebt` is still 1050, making rewards not be distributed among users because `totalUsdoDebt` < usdoSupply.
One of the possible fixes for this issue is to track debt with a storage variable. Every time a repay is performed, the difference between elastic and base could be accrued to the variable, and such variable could be decremented when the fees distributions are performed. This makes it easier to compute the actual rewards and mitigates the cross-chain issue.
Medium. The fees to be distributed in twTap are likely to always be wrong, making one of the core governance functionalities (locking TAP in order to participate in Tapioca's governance) be broken given that fee distributions (and thus the incentives to participate in governance) won't be correct.
```\\nfunction mintOpenInterestDebt(address twTap) external onlyOwner { \\n        uint256 usdoSupply = usdoToken.totalSupply();\\n\\n        // nothing to mint when there's no activity\\n        if (usdoSupply > 0) {  \\n            // re-compute latest debt\\n            uint256 totalUsdoDebt = computeTotalDebt();  \\n   \\n            //add Origins debt \\n            //Origins market doesn't accrue in time but increases totalSupply\\n            //and needs to be taken into account here\\n            uint256 len = allOriginsMarkets.length;\\n            for (uint256 i; i < len; i++) {\\n                IMarket market = IMarket(allOriginsMarkets[i]);\\n                if (isOriginRegistered[address(market)]) {\\n                    (uint256 elastic,) = market.totalBorrow();\\n                    totalUsdoDebt += elastic;\\n                }\\n            }\\n \\n            //debt should always be > USDO supply\\n            if (totalUsdoDebt > usdoSupply) { \\n                uint256 _amount = totalUsdoDebt - usdoSupply;\\n\\n                //mint against the open interest; supply should be fully minted now\\n                IUsdo(address(usdoToken)).mint(address(this), _amount);\\n\\n                //send it to twTap\\n                uint256 rewardTokenId = ITwTap(twTap).rewardTokenIndex(address(usdoToken));\\n                _distributeOnTwTap(_amount, rewardTokenId, address(usdoToken), ITwTap(twTap));\\n            }\\n        } \\n    }\\n```\\n