all files / facade/ FacadeTest.sol

94.12% Statements 32/34
80% Branches 8/10
100% Functions 4/4
94.59% Lines 35/37
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100                                                    62× 62× 62× 62× 62×   62×   855× 855×       855× 855×         855× 855×         62× 62× 855× 855×                         110× 110× 110× 110× 110×   110× 110×   1107×   887×   887× 887×   887×             33× 33×      
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
 
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IAsset.sol";
import "../interfaces/IAssetRegistry.sol";
import "../interfaces/IFacadeTest.sol";
import "../interfaces/IRToken.sol";
import "../interfaces/IStRSR.sol";
import "../libraries/Fixed.sol";
 
uint192 constant FIX_TWO = FIX_ONE * 2;
 
/**
 * @title FacadeTest
 * @notice A facade that is useful for driving/querying the system during testing.
 *   These functions should be generic to both P0 and P1.
 *
 * @custom:static-call - Use ethers callStatic() in order to get result after update
 */
contract FacadeTest is IFacadeTest {
    using FixLib for uint192;
 
    /// Prompt all traders to run auctions
    /// Relatively gas-inefficient, shouldn't be used in production. Use multicall instead
    function runAuctionsForAllTraders(IRToken rToken) external {
        IMain main = rToken.main();
        IBackingManager backingManager = main.backingManager();
        IRevenueTrader rsrTrader = main.rsrTrader();
        IRevenueTrader rTokenTrader = main.rTokenTrader();
        IERC20[] memory erc20s = main.assetRegistry().erc20s();
 
        for (uint256 i = 0; i < erc20s.length; i++) {
            // BackingManager
            ITrade trade = backingManager.trades(erc20s[i]);
            if (address(trade) != address(0) && trade.canSettle()) {
                backingManager.settleTrade(erc20s[i]);
            }
 
            // RSRTrader
            trade = rsrTrader.trades(erc20s[i]);
            Iif (address(trade) != address(0) && trade.canSettle()) {
                rsrTrader.settleTrade(erc20s[i]);
            }
 
            // RTokenTrader
            trade = rTokenTrader.trades(erc20s[i]);
            Iif (address(trade) != address(0) && trade.canSettle()) {
                rTokenTrader.settleTrade(erc20s[i]);
            }
        }
 
        main.backingManager().manageTokens(erc20s);
        for (uint256 i = 0; i < erc20s.length; i++) {
            rsrTrader.manageToken(erc20s[i]);
            rTokenTrader.manageToken(erc20s[i]);
        }
    }
 
    /// Prompt all traders and the RToken itself to claim rewards and sweep to BackingManager
    function claimRewards(IRToken rToken) external {
        IMain main = rToken.main();
        main.backingManager().claimRewards();
        main.rsrTrader().claimRewards();
        main.rTokenTrader().claimRewards();
    }
 
    /// Unlike Recollateralizationlib.totalAssetValue, this function _should_ yield a decreasing
    /// quantity through the rebalancing process due to slippage accruing during each trade.
    /// @return total {UoA} Point estimate of the value of all exogenous assets at BackingManager
    /// @custom:static-call
    function totalAssetValue(IRToken rToken) external returns (uint192 total) {
        IMain main = rToken.main();
        main.poke();
        IAssetRegistry reg = main.assetRegistry();
        address backingManager = address(main.backingManager());
        IERC20 rsr = main.rsr();
 
        IERC20[] memory erc20s = reg.erc20s();
        for (uint256 i = 0; i < erc20s.length; i++) {
            // Skip RSR + RToken
            if (erc20s[i] == rsr || erc20s[i] == IERC20(address(rToken))) continue;
 
            IAsset asset = reg.toAsset(erc20s[i]);
 
            (uint192 lowPrice, uint192 highPrice) = asset.price();
            uint192 midPrice = lowPrice.plus(highPrice).divu(2);
 
            total = total.plus(asset.bal(backingManager).mul(midPrice));
        }
    }
 
    /// @param account The account to count baskets for
    /// @return {BU} The number of whole basket units held
    function wholeBasketsHeldBy(IRToken rToken, address account) external view returns (uint192) {
        BasketRange memory range = rToken.main().basketHandler().basketsHeldBy(account);
        return range.bottom;
    }
}