all files / facade/ FacadeMonitor.sol

68.75% Statements 22/32
50% Branches 6/12
100% Functions 3/3
59.26% Lines 32/54
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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140                                                                                                                                                                                                16×   16×   16×         16× 16×            
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.17;
 
import "../libraries/Fixed.sol";
 
import "../interfaces/IAssetRegistry.sol";
import "../interfaces/IBroker.sol";
import "../p1/RToken.sol";
import "../p1/BackingManager.sol";
import "../p1/RevenueTrader.sol";
 
/**
 * @title Facade Monitor
 * @notice A UX-friendly layer for reading out the state of an RToken, specifically for the Monitor.
 * @custom:static-call - Use ethers callStatic() to get result after update; do not execute
 */
contract FacadeMonitor {
    using FixLib for uint192;
 
    struct TradeResponse {
        IERC20[] tradesToBeSettled;
        IERC20[] tradesToBeStarted;
    }
 
    function getTradesForBackingManager(RTokenP1 rToken)
        external
        returns (TradeResponse memory response)
    {
        IMain main = rToken.main();
 
        IAssetRegistry assetRegistry = IAssetRegistry(address(main.assetRegistry()));
        BackingManagerP1 backingManager = BackingManagerP1(address(main.backingManager()));
 
        IERC20[] memory erc20s = assetRegistry.erc20s();
 
        // Let's check if there are any trades that we can settle.
        Iif (backingManager.tradesOpen() > 0) {
            uint256 tradeSettleCount;
            IERC20[] memory tradesToBeSettled = new IERC20[](erc20s.length);
 
            for (uint256 i = 0; i < erc20s.length; ) {
                ITrade trade = backingManager.trades(erc20s[i]);
                if (address(trade) != address(0) && trade.canSettle()) {
                    tradesToBeSettled[tradeSettleCount] = erc20s[i];
 
                    unchecked {
                        ++tradeSettleCount;
                    }
                }
 
                unchecked {
                    ++i;
                }
            }
 
            response.tradesToBeSettled = tradesToBeSettled;
        }
 
        // Let's check if there are any trades we can start.
        uint48 tradesOpen = backingManager.tradesOpen();
        backingManager.manageTokens(erc20s);
        if (backingManager.tradesOpen() - tradesOpen != 0) {
            response.tradesToBeStarted = erc20s;
        }
    }
 
    function getTradesForRevenueTraders(RTokenP1 rToken)
        external
        returns (TradeResponse memory rTokenTraderResponse, TradeResponse memory rsrTraderResponse)
    {
        IMain main = rToken.main();
 
        IAssetRegistry assetRegistry = IAssetRegistry(address(main.assetRegistry()));
        RevenueTraderP1 rTokenTrader = RevenueTraderP1(address(main.rTokenTrader()));
        RevenueTraderP1 rsrTrader = RevenueTraderP1(address(main.rsrTrader()));
 
        IERC20[] memory erc20s = assetRegistry.erc20s();
 
        rTokenTraderResponse = getTradesForTrader(rTokenTrader, erc20s);
        rsrTraderResponse = getTradesForTrader(rsrTrader, erc20s);
    }
 
    function getTradesForTrader(RevenueTraderP1 trader, IERC20[] memory erc20s)
        internal
        returns (TradeResponse memory response)
    {
        uint256 erc20Count = erc20s.length;
 
        // Let's check if there are any trades that we can settle.
        Iif (trader.tradesOpen() > 0) {
            uint256 tradeSettleCount;
            IERC20[] memory tradesToBeSettled = new IERC20[](erc20Count);
 
            for (uint256 i = 0; i < erc20Count; ) {
                ITrade trade = trader.trades(erc20s[i]);
 
                if (address(trade) != address(0) && trade.canSettle()) {
                    tradesToBeSettled[tradeSettleCount] = erc20s[i];
 
                    unchecked {
                        ++tradeSettleCount;
                    }
                }
 
                unchecked {
                    ++i;
                }
            }
 
            response.tradesToBeSettled = tradesToBeSettled;
        }
 
        // Let's check if there are any trades we can start.
        uint48 tradesOpen = trader.tradesOpen();
        uint256 tradeStartCount;
        IERC20[] memory tradesToBeStarted = new IERC20[](erc20Count);
 
        for (uint256 i = 0; i < erc20Count; ) {
            trader.manageToken(erc20s[i]);
 
            uint48 newTradesOpen = trader.tradesOpen();
 
            if (newTradesOpen - tradesOpen != 0) {
                tradesToBeStarted[tradeStartCount] = erc20s[i];
                tradesOpen = newTradesOpen;
 
                unchecked {
                    ++tradeStartCount;
                }
            }
 
            unchecked {
                ++i;
            }
        }
 
        response.tradesToBeStarted = tradesToBeStarted;
    }
}