Medusa Coverage Report GitHub

Files

    Files
    30
    Total Lines
    3914
    Coverage
    80.0%
    483 / 604 lines
    Actions
    100.0% contracts/contracts/echidna/Debugger.sol
    Lines covered: 3 / 3 (100.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    ✓ 7
    library Debugger {
    5
        event Debug(string debugString);
    6
        event Debug(string description, string data);
    7
        event Debug(string prefix, string description, string data);
    8
        event Debug(string description, bytes32 data);
    9
        event Debug(string prefix, string description, bytes32 data);
    10
        event Debug(string description, uint256 data);
    11
        event Debug(string prefix, string description, uint256 data);
    12
        event Debug(string description, int256 data);
    13
        event Debug(string prefix, string description, int256 data);
    14
        event Debug(string description, address data);
    15
        event Debug(string prefix, string description, address data);
    16
        event Debug(string description, bool data);
    17
        event Debug(string prefix, string description, bool data);
    18
    
                                                    
                                                
    19
        function log(string memory debugString) internal {
    20
            emit Debug(debugString);
    21
        }
    22
    
                                                    
                                                
    23
        function log(string memory description, string memory data) internal {
    24
            emit Debug(description, data);
    25
        }
    26
    
                                                    
                                                
    27
        function log(
    28
            string memory prefix,
    29
            string memory description,
    30
            string memory data
    31
        ) internal {
    32
            emit Debug(prefix, description, data);
    33
        }
    34
    
                                                    
                                                
    35
        function log(string memory description, bytes32 data) internal {
    36
            emit Debug(description, data);
    37
        }
    38
    
                                                    
                                                
    39
        function log(
    40
            string memory prefix,
    41
            string memory description,
    42
            bytes32 data
    43
        ) internal {
    44
            emit Debug(prefix, description, data);
    45
        }
    46
    
                                                    
                                                
    47
        function log(string memory description, uint256 data) internal {
    48
    ✓ 182.0M
            emit Debug(description, data);
    49
        }
    50
    
                                                    
                                                
    51
        function log(
    52
            string memory prefix,
    53
            string memory description,
    54
            uint256 data
    55
        ) internal {
    56
            emit Debug(prefix, description, data);
    57
        }
    58
    
                                                    
                                                
    59
        function log(string memory description, int256 data) internal {
    60
    ✓ 10.0M
            emit Debug(description, data);
    61
        }
    62
    
                                                    
                                                
    63
        function log(
    64
            string memory prefix,
    65
            string memory description,
    66
            int256 data
    67
        ) internal {
    68
            emit Debug(prefix, description, data);
    69
        }
    70
    
                                                    
                                                
    71
        function log(string memory description, address data) internal {
    72
            emit Debug(description, data);
    73
        }
    74
    
                                                    
                                                
    75
        function log(
    76
            string memory prefix,
    77
            string memory description,
    78
            address data
    79
        ) internal {
    80
            emit Debug(prefix, description, data);
    81
        }
    82
    
                                                    
                                                
    83
        function log(string memory description, bool data) internal {
    84
            emit Debug(description, data);
    85
        }
    86
    
                                                    
                                                
    87
        function log(
    88
            string memory prefix,
    89
            string memory description,
    90
            bool data
    91
        ) internal {
    92
            emit Debug(prefix, description, data);
    93
        }
    94
    }
    95
    
                                                    
                                                
    0.0% contracts/contracts/echidna/Echidna.sol
    Lines covered: 0 / 1 (0.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./EchidnaTestApproval.sol";
    5
    
                                                    
                                                
    6
    /**
    7
     * @title Echidna test contract for OUSD
    8
     * @notice Target contract to be tested, containing all mixins
    9
     * @author Rappie
    10
     */
    11
    contract Echidna is EchidnaTestApproval {
    12
    
                                                    
                                                
    13
    }
    14
    
                                                    
                                                
    100.0% contracts/contracts/echidna/EchidnaConfig.sol
    Lines covered: 19 / 19 (100.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    /**
    5
     * @title Top-level mixin for configuring the desired fuzzing setup
    6
     * @author Rappie
    7
     */
    8
    ✓ 3
    contract EchidnaConfig {
    9
    ✓ 55.3M
        address internal constant ADDRESS_VAULT = address(0x10000);
    10
    ✓ 22.9M
        address internal constant ADDRESS_OUTSIDER_USER = address(0x20000);
    11
    
                                                    
                                                
    12
    ✓ 547.9M
        address internal constant ADDRESS_USER0 = address(0x30000);
    13
    ✓ 210.9M
        address internal constant ADDRESS_USER1 = address(0x40000);
    14
    
                                                    
                                                
    15
        // Will be set in EchidnaSetup constructor
    16
        address internal ADDRESS_OUTSIDER_CONTRACT;
    17
        address internal ADDRESS_CONTRACT0;
    18
        address internal ADDRESS_CONTRACT1;
    19
    
                                                    
                                                
    20
        // Toggle known issues
    21
        //
    22
        // This can be used to skip tests that are known to fail. This is useful
    23
        // when debugging a specific issue, but should be disabled when running
    24
        // the full test suite.
    25
        //
    26
        //   True => skip tests that are known to fail
    27
        //   False => run all tests
    28
        //
    29
        bool internal constant TOGGLE_KNOWN_ISSUES = false;
    30
    
                                                    
                                                
    31
        // Toggle known issues within limits
    32
        //
    33
        // Same as TOGGLE_KNOWN_ISSUES, but also skip tests that are known to fail
    34
        // within limits set by the variables below.
    35
        //
    36
        bool internal constant TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS = false;
    37
    
                                                    
                                                
    38
        // Starting balance
    39
        //
    40
        // Gives OUSD a non-zero starting supply, which can be useful to ignore
    41
        // certain edge cases.
    42
        //
    43
        // The starting balance is given to outsider accounts that are not used as
    44
        // accounts while fuzzing.
    45
        //
    46
        bool internal constant TOGGLE_STARTING_BALANCE = true;
    47
    ✓ 1
        uint256 internal constant STARTING_BALANCE = 1_000_000e18;
    48
    
                                                    
                                                
    49
        // Change supply
    50
        //
    51
        // Set a limit to the amount of change per rebase, which can be useful to
    52
        // ignore certain edge cases.
    53
        //
    54
        //  True => limit the amount of change to a percentage of total supply
    55
        //  False => no limit
    56
        //
    57
        bool internal constant TOGGLE_CHANGESUPPLY_LIMIT = true;
    58
    ✓ 15.9M
        uint256 internal constant CHANGESUPPLY_DIVISOR = 10; // 10% of total supply
    59
    
                                                    
                                                
    60
        // Mint limit
    61
        //
    62
        // Set a limit the amount minted per mint, which can be useful to
    63
        // ignore certain edge cases.
    64
        //
    65
        //  True => limit the amount of minted tokens
    66
        //  False => no limit
    67
        //
    68
        bool internal constant TOGGLE_MINT_LIMIT = true;
    69
    ✓ 55.3M
        uint256 internal constant MINT_MODULO = 1_000_000_000_000e18;
    70
    
                                                    
                                                
    71
        // Known rounding errors
    72
    ✓ 1.0M
        uint256 internal constant TRANSFER_ROUNDING_ERROR = 1e18 - 1;
    73
    ✓ 7.5M
        uint256 internal constant OPT_IN_ROUNDING_ERROR = 1e18 - 1;
    74
    ✓ 14.9M
        uint256 internal constant MINT_ROUNDING_ERROR = 1e18 - 1;
    75
    
                                                    
                                                
    76
        /**
    77
         * @notice Modifier to skip tests that are known to fail
    78
         * @dev see TOGGLE_KNOWN_ISSUES for more information
    79
         */
    80
        modifier hasKnownIssue() {
    81
            if (TOGGLE_KNOWN_ISSUES) return;
    82
    ✓ 71.7M
            _;
    83
        }
    84
    
                                                    
                                                
    85
        /**
    86
         * @notice Modifier to skip tests that are known to fail within limits
    87
         * @dev see TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS for more information
    88
         */
    89
        modifier hasKnownIssueWithinLimits() {
    90
            if (TOGGLE_KNOWN_ISSUES_WITHIN_LIMITS) return;
    91
            _;
    92
        }
    93
    
                                                    
                                                
    94
        /**
    95
         * @notice Translate an account ID to an address
    96
         * @param accountId The ID of the account
    97
         * @return account The address of the account
    98
         */
    99
        function getAccount(uint8 accountId)
    100
            internal
    101
            view
    102
    ✓ 1.3B
            returns (address account)
    103
        {
    104
    ✓ 1.3B
            accountId = accountId / 64;
    105
    ✓ 1.3B
            if (accountId == 0) return account = ADDRESS_USER0;
    106
    ✓ 742.3M
            if (accountId == 1) return account = ADDRESS_USER1;
    107
    ✓ 531.4M
            if (accountId == 2) return account = ADDRESS_CONTRACT0;
    108
    ✓ 338.9M
            if (accountId == 3) return account = ADDRESS_CONTRACT1;
    109
    ✓ 1.2B
            require(false, "Unknown account ID");
    110
        }
    111
    }
    112
    
                                                    
                                                
    0.0% contracts/contracts/echidna/EchidnaDebug.sol
    Lines covered: 0 / 1 (0.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import { Address } from "@openzeppelin/contracts/utils/Address.sol";
    5
    
                                                    
                                                
    6
    import "./EchidnaHelper.sol";
    7
    import "./Debugger.sol";
    8
    
                                                    
                                                
    9
    import "../token/OUSD.sol";
    10
    
                                                    
                                                
    11
    /**
    12
     * @title Room for random debugging functions
    13
     * @author Rappie
    14
     */
    15
    contract EchidnaDebug is EchidnaHelper {
    16
        function debugOUSD() public pure {
    17
            // assert(ousd.balanceOf(ADDRESS_USER0) == 1000);
    18
            // assert(ousd.rebaseState(ADDRESS_USER0) != OUSD.RebaseOptions.OptIn);
    19
            // assert(Address.isContract(ADDRESS_CONTRACT0));
    20
            // Debugger.log("nonRebasingSupply", ousd.nonRebasingSupply());
    21
            // assert(false);
    22
        }
    23
    }
    24
    
                                                    
                                                
    93.7% contracts/contracts/echidna/EchidnaHelper.sol
    Lines covered: 59 / 63 (93.7%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./EchidnaSetup.sol";
    5
    import "./Debugger.sol";
    6
    
                                                    
                                                
    7
    /**
    8
     * @title Mixin containing helper functions
    9
     * @author Rappie
    10
     */
    11
    contract EchidnaHelper is EchidnaSetup {
    12
        /**
    13
         * @notice Mint tokens to an account
    14
         * @param toAcc Account to mint to
    15
         * @param amount Amount to mint
    16
         * @return Amount minted (in case of capped mint with modulo)
    17
         */
    18
    ✓ 55.3M
        function mint(uint8 toAcc, uint256 amount) public returns (uint256) {
    19
    ✓ 55.3M
            address to = getAccount(toAcc);
    20
    
                                                    
                                                
    21
            if (TOGGLE_MINT_LIMIT) {
    22
    ✓ 55.3M
                amount = amount % MINT_MODULO;
    23
            }
    24
    
                                                    
                                                
    25
    ✓ 55.3M
            hevm.prank(ADDRESS_VAULT);
    26
    ✓ 55.3M
            ousd.mint(to, amount);
    27
    
                                                    
                                                
    28
    ✓ 54.4M
            return amount;
    29
        }
    30
    
                                                    
                                                
    31
        /**
    32
         * @notice Burn tokens from an account
    33
         * @param fromAcc Account to burn from
    34
         * @param amount Amount to burn
    35
         */
    36
        function burn(uint8 fromAcc, uint256 amount) public {
    37
    ✓ 45.5M
            address from = getAccount(fromAcc);
    38
    ✓ 45.5M
            hevm.prank(ADDRESS_VAULT);
    39
    ✓ 45.5M
            ousd.burn(from, amount);
    40
        }
    41
    
                                                    
                                                
    42
        /**
    43
         * @notice Change the total supply of OUSD (rebase)
    44
         * @param amount New total supply
    45
         */
    46
        function changeSupply(uint256 amount) public {
    47
            if (TOGGLE_CHANGESUPPLY_LIMIT) {
    48
                amount =
    49
    ✓ 15.9M
                    ousd.totalSupply() +
    50
    ✓ 15.9M
                    (amount % (ousd.totalSupply() / CHANGESUPPLY_DIVISOR));
    51
            }
    52
    
                                                    
                                                
    53
    ✓ 15.9M
            hevm.prank(ADDRESS_VAULT);
    54
    ✓ 15.9M
            ousd.changeSupply(amount);
    55
        }
    56
    
                                                    
                                                
    57
        /**
    58
         * @notice Transfer tokens between accounts
    59
         * @param fromAcc Account to transfer from
    60
         * @param toAcc Account to transfer to
    61
         * @param amount Amount to transfer
    62
         */
    63
        function transfer(
    64
            uint8 fromAcc,
    65
            uint8 toAcc,
    66
            uint256 amount
    67
        ) public {
    68
    ✓ 116.0M
            address from = getAccount(fromAcc);
    69
    ✓ 116.0M
            address to = getAccount(toAcc);
    70
    ✓ 116.0M
            hevm.prank(from);
    71
            // slither-disable-next-line unchecked-transfer
    72
    ✓ 116.0M
            ousd.transfer(to, amount);
    73
        }
    74
    
                                                    
                                                
    75
        /**
    76
         * @notice Transfer approved tokens between accounts
    77
         * @param authorizedAcc Account that is authorized to transfer
    78
         * @param fromAcc Account to transfer from
    79
         * @param toAcc Account to transfer to
    80
         * @param amount Amount to transfer
    81
         */
    82
        function transferFrom(
    83
            uint8 authorizedAcc,
    84
            uint8 fromAcc,
    85
            uint8 toAcc,
    86
            uint256 amount
    87
        ) public {
    88
    ✓ 11.6M
            address authorized = getAccount(authorizedAcc);
    89
    ✓ 11.6M
            address from = getAccount(fromAcc);
    90
    ✓ 11.6M
            address to = getAccount(toAcc);
    91
    ✓ 11.6M
            hevm.prank(authorized);
    92
            // slither-disable-next-line unchecked-transfer
    93
    ✓ 11.6M
            ousd.transferFrom(from, to, amount);
    94
        }
    95
    
                                                    
                                                
    96
        /**
    97
         * @notice Opt in to rebasing
    98
         * @param targetAcc Account to opt in
    99
         */
    100
        function optIn(uint8 targetAcc) public {
    101
    ✓ 74.2M
            address target = getAccount(targetAcc);
    102
    ✓ 74.2M
            hevm.prank(target);
    103
    ✓ 74.2M
            ousd.rebaseOptIn();
    104
        }
    105
    
                                                    
                                                
    106
        /**
    107
         * @notice Opt out of rebasing
    108
         * @param targetAcc Account to opt out
    109
         */
    110
        function optOut(uint8 targetAcc) public {
    111
    ✓ 72.7M
            address target = getAccount(targetAcc);
    112
    ✓ 72.7M
            hevm.prank(target);
    113
    ✓ 72.7M
            ousd.rebaseOptOut();
    114
        }
    115
    
                                                    
                                                
    116
        /**
    117
         * @notice Approve an account to spend OUSD
    118
         * @param ownerAcc Account that owns the OUSD
    119
         * @param spenderAcc Account that is approved to spend the OUSD
    120
         * @param amount Amount to approve
    121
         */
    122
        function approve(
    123
            uint8 ownerAcc,
    124
            uint8 spenderAcc,
    125
            uint256 amount
    126
        ) public {
    127
    ✓ 46.1M
            address owner = getAccount(ownerAcc);
    128
    ✓ 46.1M
            address spender = getAccount(spenderAcc);
    129
    ✓ 46.1M
            hevm.prank(owner);
    130
            // slither-disable-next-line unused-return
    131
    ✓ 46.1M
            ousd.approve(spender, amount);
    132
        }
    133
    
                                                    
                                                
    134
        /**
    135
         * @notice Get the sum of all OUSD balances
    136
         * @return total Total balance
    137
         */
    138
    ✓ 11.4M
        function getTotalBalance() public view returns (uint256 total) {
    139
    ✓ 11.4M
            total += ousd.balanceOf(ADDRESS_VAULT);
    140
    ✓ 11.4M
            total += ousd.balanceOf(ADDRESS_OUTSIDER_USER);
    141
    ✓ 11.4M
            total += ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT);
    142
    ✓ 11.4M
            total += ousd.balanceOf(ADDRESS_USER0);
    143
    ✓ 11.4M
            total += ousd.balanceOf(ADDRESS_USER1);
    144
    ✓ 11.4M
            total += ousd.balanceOf(ADDRESS_CONTRACT0);
    145
    ✓ 11.4M
            total += ousd.balanceOf(ADDRESS_CONTRACT1);
    146
        }
    147
    
                                                    
                                                
    148
        /**
    149
         * @notice Get the sum of all non-rebasing OUSD balances
    150
         * @return total Total balance
    151
         */
    152
    ✓ 22.9M
        function getTotalNonRebasingBalance() public returns (uint256 total) {
    153
    ✓ 22.9M
            total += ousd._isNonRebasingAccountEchidna(ADDRESS_VAULT)
    154
                ? ousd.balanceOf(ADDRESS_VAULT)
    155
    ✓ 22.9M
                : 0;
    156
    ✓ 22.9M
            total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_USER)
    157
                ? ousd.balanceOf(ADDRESS_OUTSIDER_USER)
    158
    ✓ 22.9M
                : 0;
    159
    ✓ 22.9M
            total += ousd._isNonRebasingAccountEchidna(ADDRESS_OUTSIDER_CONTRACT)
    160
    ✓ 22.9M
                ? ousd.balanceOf(ADDRESS_OUTSIDER_CONTRACT)
    161
                : 0;
    162
    ✓ 22.9M
            total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER0)
    163
    ✓ 13.4M
                ? ousd.balanceOf(ADDRESS_USER0)
    164
    ✓ 9.5M
                : 0;
    165
    ✓ 22.9M
            total += ousd._isNonRebasingAccountEchidna(ADDRESS_USER1)
    166
    ✓ 4.9M
                ? ousd.balanceOf(ADDRESS_USER1)
    167
    ✓ 18.0M
                : 0;
    168
    ✓ 22.9M
            total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT0)
    169
    ✓ 17.8M
                ? ousd.balanceOf(ADDRESS_CONTRACT0)
    170
    ✓ 5.1M
                : 0;
    171
    ✓ 22.9M
            total += ousd._isNonRebasingAccountEchidna(ADDRESS_CONTRACT1)
    172
    ✓ 12.5M
                ? ousd.balanceOf(ADDRESS_CONTRACT1)
    173
    ✓ 10.3M
                : 0;
    174
        }
    175
    }
    176
    
                                                    
                                                
    93.3% contracts/contracts/echidna/EchidnaSetup.sol
    Lines covered: 14 / 15 (93.3%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./IHevm.sol";
    5
    import "./EchidnaConfig.sol";
    6
    import "./OUSDEchidna.sol";
    7
    
                                                    
                                                
    8
    ✓ 3
    contract Dummy {}
    9
    
                                                    
                                                
    10
    /**
    11
     * @title Mixin for setup and deployment
    12
     * @author Rappie
    13
     */
    14
    contract EchidnaSetup is EchidnaConfig {
    15
    ✓ 1
        IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
    16
    ✓ 1
        OUSDEchidna ousd = new OUSDEchidna();
    17
    
                                                    
                                                
    18
        /**
    19
         * @notice Deploy the OUSD contract and set up initial state
    20
         */
    21
        constructor() {
    22
    ✓ 1
            ousd.initialize(ADDRESS_VAULT, 1e18);
    23
    
                                                    
                                                
    24
            // Deploy dummny contracts as users
    25
    ✓ 1
            Dummy outsider = new Dummy();
    26
    ✓ 1
            ADDRESS_OUTSIDER_CONTRACT = address(outsider);
    27
    ✓ 1
            Dummy dummy0 = new Dummy();
    28
    ✓ 1
            ADDRESS_CONTRACT0 = address(dummy0);
    29
    ✓ 1
            Dummy dummy1 = new Dummy();
    30
    ✓ 1
            ADDRESS_CONTRACT1 = address(dummy1);
    31
    
                                                    
                                                
    32
            // Start out with a reasonable amount of OUSD
    33
            if (TOGGLE_STARTING_BALANCE) {
    34
                // Rebasing tokens
    35
    ✓ 1
                hevm.prank(ADDRESS_VAULT);
    36
    ✓ 1
                ousd.mint(ADDRESS_OUTSIDER_USER, STARTING_BALANCE / 2);
    37
    
                                                    
                                                
    38
                // Non-rebasing tokens
    39
    ✓ 1
                hevm.prank(ADDRESS_VAULT);
    40
    ✓ 1
                ousd.mint(ADDRESS_OUTSIDER_CONTRACT, STARTING_BALANCE / 2);
    41
            }
    42
        }
    43
    }
    44
    
                                                    
                                                
    90.9% contracts/contracts/echidna/EchidnaTestAccounting.sol
    Lines covered: 30 / 33 (90.9%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./EchidnaDebug.sol";
    5
    import "./EchidnaTestSupply.sol";
    6
    
                                                    
                                                
    7
    /**
    8
     * @title Mixin for testing accounting functions
    9
     * @author Rappie
    10
     */
    11
    contract EchidnaTestAccounting is EchidnaTestSupply {
    12
        /**
    13
         * @notice After opting in, balance should not increase. (Ok to lose rounding funds doing this)
    14
         * @param targetAcc Account to opt in
    15
         */
    16
        function testOptInBalance(uint8 targetAcc) public {
    17
    ✓ 15.2M
            address target = getAccount(targetAcc);
    18
    
                                                    
                                                
    19
    ✓ 15.2M
            uint256 balanceBefore = ousd.balanceOf(target);
    20
    ✓ 15.2M
            optIn(targetAcc);
    21
    ✓ 8.2M
            uint256 balanceAfter = ousd.balanceOf(target);
    22
    
                                                    
                                                
    23
    ✓ 8.2M
            assert(balanceAfter <= balanceBefore);
    24
        }
    25
    
                                                    
                                                
    26
        /**
    27
         * @notice After opting out, balance should remain the same
    28
         * @param targetAcc Account to opt out
    29
         */
    30
        function testOptOutBalance(uint8 targetAcc) public {
    31
    ✓ 15.5M
            address target = getAccount(targetAcc);
    32
    
                                                    
                                                
    33
    ✓ 15.5M
            uint256 balanceBefore = ousd.balanceOf(target);
    34
    ✓ 15.5M
            optOut(targetAcc);
    35
    ✓ 15.5M
            uint256 balanceAfter = ousd.balanceOf(target);
    36
    
                                                    
                                                
    37
            assert(balanceAfter == balanceBefore);
    38
        }
    39
    
                                                    
                                                
    40
        /**
    41
         * @notice Account balance should remain the same after opting in minus rounding error
    42
         * @param targetAcc Account to opt in
    43
         */
    44
        function testOptInBalanceRounding(uint8 targetAcc) public {
    45
    ✓ 15.3M
            address target = getAccount(targetAcc);
    46
    
                                                    
                                                
    47
    ✓ 15.3M
            uint256 balanceBefore = ousd.balanceOf(target);
    48
    ✓ 15.3M
            optIn(targetAcc);
    49
    ✓ 7.9M
            uint256 balanceAfter = ousd.balanceOf(target);
    50
    
                                                    
                                                
    51
    ✓ 7.9M
            int256 delta = int256(balanceAfter) - int256(balanceBefore);
    52
    ✓ 7.9M
            Debugger.log("delta", delta);
    53
    
                                                    
                                                
    54
            // slither-disable-next-line tautology
    55
    ✓ 7.9M
            assert(-1 * delta >= 0);
    56
    ✓ 7.5M
            assert(-1 * delta <= int256(OPT_IN_ROUNDING_ERROR));
    57
        }
    58
    
                                                    
                                                
    59
        /**
    60
         * @notice After opting in, total supply should remain the same
    61
         * @param targetAcc Account to opt in
    62
         */
    63
        function testOptInTotalSupply(uint8 targetAcc) public {
    64
    ✓ 15.4M
            uint256 totalSupplyBefore = ousd.totalSupply();
    65
    ✓ 15.4M
            optIn(targetAcc);
    66
            uint256 totalSupplyAfter = ousd.totalSupply();
    67
    
                                                    
                                                
    68
            assert(totalSupplyAfter == totalSupplyBefore);
    69
        }
    70
    
                                                    
                                                
    71
        /**
    72
         * @notice After opting out, total supply should remain the same
    73
         * @param targetAcc Account to opt out
    74
         */
    75
        function testOptOutTotalSupply(uint8 targetAcc) public {
    76
    ✓ 24.6M
            uint256 totalSupplyBefore = ousd.totalSupply();
    77
    ✓ 24.6M
            optOut(targetAcc);
    78
    ✓ 20.9M
            uint256 totalSupplyAfter = ousd.totalSupply();
    79
    
                                                    
                                                
    80
    ✓ 20.9M
            assert(totalSupplyAfter == totalSupplyBefore);
    81
        }
    82
    
                                                    
                                                
    83
        /**
    84
         * @notice Account balance should remain the same when a smart contract auto converts
    85
         * @param targetAcc Account to auto convert
    86
         */
    87
        function testAutoConvertBalance(uint8 targetAcc) public {
    88
    ✓ 24.7M
            address target = getAccount(targetAcc);
    89
    
                                                    
                                                
    90
    ✓ 24.7M
            uint256 balanceBefore = ousd.balanceOf(target);
    91
            // slither-disable-next-line unused-return
    92
    ✓ 24.7M
            ousd._isNonRebasingAccountEchidna(target);
    93
    ✓ 36.0M
            uint256 balanceAfter = ousd.balanceOf(target);
    94
    
                                                    
                                                
    95
    ✓ 51.5M
            assert(balanceAfter == balanceBefore);
    96
        }
    97
    
                                                    
                                                
    98
        /**
    99
         * @notice The `balanceOf` function should never revert
    100
         * @param targetAcc Account to check balance of
    101
         */
    102
        function testBalanceOfShouldNotRevert(uint8 targetAcc) public {
    103
    ✓ 15.5M
            address target = getAccount(targetAcc);
    104
    
                                                    
                                                
    105
            // slither-disable-next-line unused-return
    106
    ✓ 15.5M
            try ousd.balanceOf(target) {
    107
                assert(true);
    108
            } catch {
    109
                assert(false);
    110
            }
    111
        }
    112
    }
    113
    
                                                    
                                                
    96.2% contracts/contracts/echidna/EchidnaTestApproval.sol
    Lines covered: 25 / 26 (96.2%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./EchidnaTestMintBurn.sol";
    5
    import "./Debugger.sol";
    6
    
                                                    
                                                
    7
    /**
    8
     * @title Mixin for testing approval related functions
    9
     * @author Rappie
    10
     */
    11
    contract EchidnaTestApproval is EchidnaTestMintBurn {
    12
        /**
    13
         * @notice Performing `transferFrom` with an amount inside the allowance should not revert
    14
         * @param authorizedAcc The account that is authorized to transfer
    15
         * @param fromAcc The account that is transferring
    16
         * @param toAcc The account that is receiving
    17
         * @param amount The amount to transfer
    18
         */
    19
        function testTransferFromShouldNotRevert(
    20
            uint8 authorizedAcc,
    21
            uint8 fromAcc,
    22
            uint8 toAcc,
    23
            uint256 amount
    24
        ) public {
    25
    ✓ 32.2M
            address authorized = getAccount(authorizedAcc);
    26
    ✓ 32.2M
            address from = getAccount(fromAcc);
    27
    ✓ 32.2M
            address to = getAccount(toAcc);
    28
    
                                                    
                                                
    29
    ✓ 32.2M
            require(amount <= ousd.balanceOf(from));
    30
    ✓ 4.7M
            require(amount <= ousd.allowance(from, authorized));
    31
    
                                                    
                                                
    32
    ✓ 4.1M
            hevm.prank(authorized);
    33
            // slither-disable-next-line unchecked-transfer
    34
    ✓ 4.1M
            try ousd.transferFrom(from, to, amount) {
    35
                // pass
    36
            } catch {
    37
    ✓ 3.1M
                assert(false);
    38
            }
    39
        }
    40
    
                                                    
                                                
    41
        /**
    42
         * @notice Performing `transferFrom` with an amount outside the allowance should revert
    43
         * @param authorizedAcc The account that is authorized to transfer
    44
         * @param fromAcc The account that is transferring
    45
         * @param toAcc The account that is receiving
    46
         * @param amount The amount to transfer
    47
         */
    48
        function testTransferFromShouldRevert(
    49
            uint8 authorizedAcc,
    50
            uint8 fromAcc,
    51
            uint8 toAcc,
    52
            uint256 amount
    53
        ) public {
    54
    ✓ 19.5M
            address authorized = getAccount(authorizedAcc);
    55
    ✓ 19.5M
            address from = getAccount(fromAcc);
    56
    ✓ 19.5M
            address to = getAccount(toAcc);
    57
    
                                                    
                                                
    58
    ✓ 19.5M
            require(amount > 0);
    59
            require(
    60
    ✓ 19.2M
                !(amount <= ousd.balanceOf(from) &&
    61
    ✓ 943.0K
                    amount <= ousd.allowance(from, authorized))
    62
            );
    63
    
                                                    
                                                
    64
    ✓ 19.1M
            hevm.prank(authorized);
    65
            // slither-disable-next-line unchecked-transfer
    66
    ✓ 19.1M
            try ousd.transferFrom(from, to, amount) {
    67
    ✓ 56.5M
                assert(false);
    68
            } catch {
    69
                // pass
    70
            }
    71
        }
    72
    
                                                    
                                                
    73
        /**
    74
         * @notice Approving an amount should update the allowance and overwrite any previous allowance
    75
         * @param ownerAcc The account that is approving
    76
         * @param spenderAcc The account that is being approved
    77
         * @param amount The amount to approve
    78
         */
    79
        function testApprove(
    80
            uint8 ownerAcc,
    81
            uint8 spenderAcc,
    82
            uint256 amount
    83
        ) public {
    84
    ✓ 11.2M
            address owner = getAccount(ownerAcc);
    85
    ✓ 11.2M
            address spender = getAccount(spenderAcc);
    86
    
                                                    
                                                
    87
    ✓ 11.2M
            approve(ownerAcc, spenderAcc, amount);
    88
    ✓ 11.2M
            uint256 allowanceAfter1 = ousd.allowance(owner, spender);
    89
    
                                                    
                                                
    90
    ✓ 11.2M
            assert(allowanceAfter1 == amount);
    91
    
                                                    
                                                
    92
    ✓ 11.2M
            approve(ownerAcc, spenderAcc, amount / 2);
    93
    ✓ 11.2M
            uint256 allowanceAfter2 = ousd.allowance(owner, spender);
    94
    
                                                    
                                                
    95
    ✓ 11.2M
            assert(allowanceAfter2 == amount / 2);
    96
        }
    97
    }
    98
    
                                                    
                                                
    94.7% contracts/contracts/echidna/EchidnaTestMintBurn.sol
    Lines covered: 36 / 38 (94.7%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./EchidnaDebug.sol";
    5
    import "./EchidnaTestAccounting.sol";
    6
    
                                                    
                                                
    7
    /**
    8
     * @title Mixin for testing Mint and Burn functions
    9
     * @author Rappie
    10
     */
    11
    contract EchidnaTestMintBurn is EchidnaTestAccounting {
    12
        /**
    13
         * @notice Minting 0 tokens should not affect account balance
    14
         * @param targetAcc Account to mint to
    15
         */
    16
        function testMintZeroBalance(uint8 targetAcc) public {
    17
    ✓ 11.3M
            address target = getAccount(targetAcc);
    18
    
                                                    
                                                
    19
    ✓ 11.3M
            uint256 balanceBefore = ousd.balanceOf(target);
    20
    ✓ 11.3M
            mint(targetAcc, 0);
    21
            uint256 balanceAfter = ousd.balanceOf(target);
    22
    
                                                    
                                                
    23
            assert(balanceAfter == balanceBefore);
    24
        }
    25
    
                                                    
                                                
    26
        /**
    27
         * @notice Burning 0 tokens should not affect account balance
    28
         * @param targetAcc Account to burn from
    29
         */
    30
        function testBurnZeroBalance(uint8 targetAcc) public {
    31
    ✓ 7.1M
            address target = getAccount(targetAcc);
    32
    
                                                    
                                                
    33
    ✓ 7.1M
            uint256 balanceBefore = ousd.balanceOf(target);
    34
    ✓ 7.1M
            burn(targetAcc, 0);
    35
            uint256 balanceAfter = ousd.balanceOf(target);
    36
    
                                                    
                                                
    37
            assert(balanceAfter == balanceBefore);
    38
        }
    39
    
                                                    
                                                
    40
        /**
    41
         * @notice Minting tokens must increase the account balance by at least amount
    42
         * @param targetAcc Account to mint to
    43
         * @param amount Amount to mint
    44
         * @custom:error testMintBalance(uint8,uint256): failed!💥
    45
         *   Call sequence:
    46
         *       changeSupply(1)
    47
         *       testMintBalance(0,1)
    48
         *   Event sequence:
    49
         *       Debug(«balanceBefore», 0)
    50
         *       Debug(«balanceAfter», 0)
    51
         */
    52
        function testMintBalance(uint8 targetAcc, uint256 amount)
    53
            public
    54
            hasKnownIssue
    55
            hasKnownIssueWithinLimits
    56
        {
    57
    ✓ 11.7M
            address target = getAccount(targetAcc);
    58
    
                                                    
                                                
    59
    ✓ 11.7M
            uint256 balanceBefore = ousd.balanceOf(target);
    60
    ✓ 11.7M
            uint256 amountMinted = mint(targetAcc, amount);
    61
    ✓ 11.4M
            uint256 balanceAfter = ousd.balanceOf(target);
    62
    
                                                    
                                                
    63
    ✓ 11.4M
            Debugger.log("amountMinted", amountMinted);
    64
    ✓ 11.4M
            Debugger.log("balanceBefore", balanceBefore);
    65
    ✓ 11.4M
            Debugger.log("balanceAfter", balanceAfter);
    66
    
                                                    
                                                
    67
    ✓ 11.4M
            assert(balanceAfter >= balanceBefore + amountMinted);
    68
        }
    69
    
                                                    
                                                
    70
        /**
    71
         * @notice Burning tokens must decrease the account balance by at least amount
    72
         * @param targetAcc Account to burn from
    73
         * @param amount Amount to burn
    74
         * @custom:error testBurnBalance(uint8,uint256): failed!💥
    75
         *   Call sequence:
    76
         *       changeSupply(1)
    77
         *       mint(0,3)
    78
         *       testBurnBalance(0,1)
    79
         *   Event sequence:
    80
         *       Debug(«balanceBefore», 2)
    81
         *       Debug(«balanceAfter», 2)
    82
         */
    83
        function testBurnBalance(uint8 targetAcc, uint256 amount)
    84
            public
    85
            hasKnownIssue
    86
            hasKnownIssueWithinLimits
    87
        {
    88
    ✓ 7.3M
            address target = getAccount(targetAcc);
    89
    
                                                    
                                                
    90
    ✓ 7.3M
            uint256 balanceBefore = ousd.balanceOf(target);
    91
    ✓ 7.3M
            burn(targetAcc, amount);
    92
    ✓ 749.9K
            uint256 balanceAfter = ousd.balanceOf(target);
    93
    
                                                    
                                                
    94
    ✓ 749.9K
            Debugger.log("balanceBefore", balanceBefore);
    95
    ✓ 749.9K
            Debugger.log("balanceAfter", balanceAfter);
    96
    
                                                    
                                                
    97
    ✓ 749.9K
            assert(balanceAfter <= balanceBefore - amount);
    98
        }
    99
    
                                                    
                                                
    100
        /**
    101
         * @notice Minting tokens should not increase the account balance by less than rounding error above amount
    102
         * @param targetAcc Account to mint to
    103
         * @param amount Amount to mint
    104
         */
    105
        function testMintBalanceRounding(uint8 targetAcc, uint256 amount) public {
    106
    ✓ 16.0M
            address target = getAccount(targetAcc);
    107
    
                                                    
                                                
    108
    ✓ 16.0M
            uint256 balanceBefore = ousd.balanceOf(target);
    109
    ✓ 16.0M
            uint256 amountMinted = mint(targetAcc, amount);
    110
    ✓ 15.6M
            uint256 balanceAfter = ousd.balanceOf(target);
    111
    
                                                    
                                                
    112
    ✓ 15.6M
            int256 delta = int256(balanceAfter) - int256(balanceBefore);
    113
    
                                                    
                                                
    114
            // delta == amount, if no error
    115
            // delta < amount,  if too little is minted
    116
            // delta > amount,  if too much is minted
    117
    ✓ 15.6M
            int256 error = int256(amountMinted) - delta;
    118
    
                                                    
                                                
    119
    ✓ 15.6M
            assert(error >= 0);
    120
    ✓ 14.9M
            assert(error <= int256(MINT_ROUNDING_ERROR));
    121
        }
    122
    
                                                    
                                                
    123
        /**
    124
         * @notice A burn of an account balance must result in a zero balance
    125
         * @param targetAcc Account to burn from
    126
         */
    127
        function testBurnAllBalanceToZero(uint8 targetAcc) public hasKnownIssue {
    128
    ✓ 15.5M
            address target = getAccount(targetAcc);
    129
    
                                                    
                                                
    130
    ✓ 15.5M
            burn(targetAcc, ousd.balanceOf(target));
    131
    ✓ 15.5M
            assert(ousd.balanceOf(target) == 0);
    132
        }
    133
    
                                                    
                                                
    134
        /**
    135
         * @notice You should always be able to burn an account's balance
    136
         * @param targetAcc Account to burn from
    137
         */
    138
        function testBurnAllBalanceShouldNotRevert(uint8 targetAcc)
    139
            public
    140
            hasKnownIssue
    141
        {
    142
    ✓ 24.3M
            address target = getAccount(targetAcc);
    143
    ✓ 24.3M
            uint256 balance = ousd.balanceOf(target);
    144
    
                                                    
                                                
    145
    ✓ 24.3M
            hevm.prank(ADDRESS_VAULT);
    146
    ✓ 24.3M
            try ousd.burn(target, balance) {
    147
                assert(true);
    148
            } catch {
    149
                assert(false);
    150
            }
    151
        }
    152
    }
    153
    
                                                    
                                                
    100.0% contracts/contracts/echidna/EchidnaTestSupply.sol
    Lines covered: 32 / 32 (100.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./EchidnaDebug.sol";
    5
    import "./EchidnaTestTransfer.sol";
    6
    
                                                    
                                                
    7
    import { StableMath } from "../utils/StableMath.sol";
    8
    
                                                    
                                                
    9
    /**
    10
     * @title Mixin for testing supply related functions
    11
     * @author Rappie
    12
     */
    13
    contract EchidnaTestSupply is EchidnaTestTransfer {
    14
        using StableMath for uint256;
    15
    
                                                    
                                                
    16
    ✓ 1
        uint256 prevRebasingCreditsPerToken = type(uint256).max;
    17
    
                                                    
                                                
    18
        /**
    19
         * @notice After a `changeSupply`, the total supply should exactly
    20
         * match the target total supply. (This is needed to ensure successive
    21
         * rebases are correct).
    22
         * @param supply New total supply
    23
         * @custom:error testChangeSupply(uint256): failed!💥
    24
         *   Call sequence:
    25
         *       testChangeSupply(1044505275072865171609)
    26
         *   Event sequence:
    27
         *       TotalSupplyUpdatedHighres(1044505275072865171610, 1000000000000000000000000, 957391048054055578595)
    28
         */
    29
        function testChangeSupply(uint256 supply)
    30
            public
    31
            hasKnownIssue
    32
            hasKnownIssueWithinLimits
    33
        {
    34
    ✓ 15.4M
            hevm.prank(ADDRESS_VAULT);
    35
    ✓ 15.4M
            ousd.changeSupply(supply);
    36
    
                                                    
                                                
    37
    ✓ 13.7M
            assert(ousd.totalSupply() == supply);
    38
        }
    39
    
                                                    
                                                
    40
        /**
    41
         * @notice The total supply must not be less than the sum of account balances.
    42
         * (The difference will go into future rebases)
    43
         * @custom:error testTotalSupplyLessThanTotalBalance(): failed!💥
    44
         *   Call sequence:
    45
         *     mint(0,1)
    46
         *     changeSupply(1)
    47
         *     optOut(64)
    48
         *     transfer(0,64,1)
    49
         *     testTotalSupplyLessThanTotalBalance()
    50
         *   Event sequence:
    51
         *     Debug(«totalSupply», 1000000000000000001000001)
    52
         *     Debug(«totalBalance», 1000000000000000001000002)
    53
         */
    54
        function testTotalSupplyLessThanTotalBalance()
    55
            public
    56
            hasKnownIssue
    57
            hasKnownIssueWithinLimits
    58
        {
    59
    ✓ 11.3M
            uint256 totalSupply = ousd.totalSupply();
    60
    ✓ 11.3M
            uint256 totalBalance = getTotalBalance();
    61
    
                                                    
                                                
    62
    ✓ 11.3M
            Debugger.log("totalSupply", totalSupply);
    63
    ✓ 11.3M
            Debugger.log("totalBalance", totalBalance);
    64
    
                                                    
                                                
    65
            assert(totalSupply >= totalBalance);
    66
        }
    67
    
                                                    
                                                
    68
        /**
    69
         * @notice Non-rebasing supply should not be larger than total supply
    70
         * @custom:error testNonRebasingSupplyVsTotalSupply(): failed!💥
    71
         *   Call sequence:
    72
         *     mint(0,2)
    73
         *     changeSupply(3)
    74
         *     burn(0,1)
    75
         *     optOut(0)
    76
         *     testNonRebasingSupplyVsTotalSupply()
    77
         */
    78
        function testNonRebasingSupplyVsTotalSupply() public hasKnownIssue {
    79
    ✓ 11.6M
            uint256 nonRebasingSupply = ousd.nonRebasingSupply();
    80
    ✓ 11.6M
            uint256 totalSupply = ousd.totalSupply();
    81
    
                                                    
                                                
    82
    ✓ 11.6M
            assert(nonRebasingSupply <= totalSupply);
    83
        }
    84
    
                                                    
                                                
    85
        /**
    86
         * @notice Global `rebasingCreditsPerToken` should never increase
    87
         * @custom:error testRebasingCreditsPerTokenNotIncreased(): failed!💥
    88
         *   Call sequence:
    89
         *     testRebasingCreditsPerTokenNotIncreased()
    90
         *     changeSupply(1)
    91
         *     testRebasingCreditsPerTokenNotIncreased()
    92
         */
    93
        function testRebasingCreditsPerTokenNotIncreased() public hasKnownIssue {
    94
    ✓ 15.2M
            uint256 curRebasingCreditsPerToken = ousd
    95
                .rebasingCreditsPerTokenHighres();
    96
    
                                                    
                                                
    97
    ✓ 15.2M
            Debugger.log(
    98
                "prevRebasingCreditsPerToken",
    99
    ✓ 15.2M
                prevRebasingCreditsPerToken
    100
            );
    101
    ✓ 15.2M
            Debugger.log("curRebasingCreditsPerToken", curRebasingCreditsPerToken);
    102
    
                                                    
                                                
    103
    ✓ 15.2M
            assert(curRebasingCreditsPerToken <= prevRebasingCreditsPerToken);
    104
    
                                                    
                                                
    105
    ✓ 11.0M
            prevRebasingCreditsPerToken = curRebasingCreditsPerToken;
    106
        }
    107
    
                                                    
                                                
    108
        /**
    109
         * @notice The rebasing credits per token ratio must greater than zero
    110
         */
    111
        function testRebasingCreditsPerTokenAboveZero() public {
    112
    ✓ 11.3M
            assert(ousd.rebasingCreditsPerTokenHighres() > 0);
    113
        }
    114
    
                                                    
                                                
    115
        /**
    116
         * @notice The sum of all non-rebasing balances should not be larger than
    117
         * non-rebasing supply
    118
         * @custom:error testTotalNonRebasingSupplyLessThanTotalBalance(): failed!💥
    119
         *   Call sequence
    120
         *     mint(0,2)
    121
         *     changeSupply(1)
    122
         *     optOut(0)
    123
         *     burn(0,1)
    124
         *     testTotalNonRebasingSupplyLessThanTotalBalance()
    125
         *   Event sequence:
    126
         *     Debug(«totalNonRebasingSupply», 500000000000000000000001)
    127
         *     Debug(«totalNonRebasingBalance», 500000000000000000000002)
    128
         */
    129
        function testTotalNonRebasingSupplyLessThanTotalBalance()
    130
            public
    131
            hasKnownIssue
    132
            hasKnownIssueWithinLimits
    133
        {
    134
    ✓ 15.5M
            uint256 totalNonRebasingSupply = ousd.nonRebasingSupply();
    135
    ✓ 15.5M
            uint256 totalNonRebasingBalance = getTotalNonRebasingBalance();
    136
    
                                                    
                                                
    137
    ✓ 15.5M
            Debugger.log("totalNonRebasingSupply", totalNonRebasingSupply);
    138
    ✓ 15.5M
            Debugger.log("totalNonRebasingBalance", totalNonRebasingBalance);
    139
    
                                                    
                                                
    140
    ✓ 26.8M
            assert(totalNonRebasingSupply >= totalNonRebasingBalance);
    141
        }
    142
    
                                                    
                                                
    143
        /**
    144
         * @notice An accounts credits / credits per token should not be larger it's balance
    145
         * @param targetAcc The account to check
    146
         */
    147
        function testCreditsPerTokenVsBalance(uint8 targetAcc) public {
    148
    ✓ 11.3M
            address target = getAccount(targetAcc);
    149
    
                                                    
                                                
    150
    ✓ 11.3M
            (uint256 credits, uint256 creditsPerToken, ) = ousd
    151
                .creditsBalanceOfHighres(target);
    152
    ✓ 11.3M
            uint256 expectedBalance = credits.divPrecisely(creditsPerToken);
    153
    
                                                    
                                                
    154
    ✓ 11.3M
            uint256 balance = ousd.balanceOf(target);
    155
    
                                                    
                                                
    156
    ✓ 11.3M
            Debugger.log("credits", credits);
    157
    ✓ 11.3M
            Debugger.log("creditsPerToken", creditsPerToken);
    158
    ✓ 11.3M
            Debugger.log("expectedBalance", expectedBalance);
    159
    ✓ 11.3M
            Debugger.log("balance", balance);
    160
    
                                                    
                                                
    161
    ✓ 11.3M
            assert(expectedBalance == balance);
    162
        }
    163
    }
    164
    
                                                    
                                                
    96.8% contracts/contracts/echidna/EchidnaTestTransfer.sol
    Lines covered: 91 / 94 (96.8%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "./EchidnaDebug.sol";
    5
    import "./Debugger.sol";
    6
    
                                                    
                                                
    7
    /**
    8
     * @title Mixin for testing transfer related functions
    9
     * @author Rappie
    10
     */
    11
    contract EchidnaTestTransfer is EchidnaDebug {
    12
        /**
    13
         * @notice The receiving account's balance after a transfer must not increase by
    14
         * less than the amount transferred
    15
         * @param fromAcc Account to transfer from
    16
         * @param toAcc Account to transfer to
    17
         * @param amount Amount to transfer
    18
         * @custom:error testTransferBalanceReceivedLess(uint8,uint8,uint256): failed!💥
    19
         *   Call sequence:
    20
         *     changeSupply(1)
    21
         *     mint(64,2)
    22
         *     testTransferBalanceReceivedLess(64,0,1)
    23
         *   Event sequence:
    24
         *     Debug(«totalSupply», 1000000000000000000500002)
    25
         *     Debug(«toBalBefore», 0)
    26
         *     Debug(«toBalAfter», 0)
    27
         */
    28
        function testTransferBalanceReceivedLess(
    29
            uint8 fromAcc,
    30
            uint8 toAcc,
    31
            uint256 amount
    32
        ) public hasKnownIssue hasKnownIssueWithinLimits {
    33
    ✓ 16.2M
            address from = getAccount(fromAcc);
    34
    ✓ 16.2M
            address to = getAccount(toAcc);
    35
    
                                                    
                                                
    36
    ✓ 16.2M
            require(from != to);
    37
    
                                                    
                                                
    38
    ✓ 9.9M
            uint256 toBalBefore = ousd.balanceOf(to);
    39
    ✓ 9.9M
            transfer(fromAcc, toAcc, amount);
    40
    ✓ 511.9K
            uint256 toBalAfter = ousd.balanceOf(to);
    41
    
                                                    
                                                
    42
    ✓ 511.9K
            Debugger.log("totalSupply", ousd.totalSupply());
    43
    ✓ 511.9K
            Debugger.log("toBalBefore", toBalBefore);
    44
    ✓ 511.9K
            Debugger.log("toBalAfter", toBalAfter);
    45
    
                                                    
                                                
    46
    ✓ 511.9K
            assert(toBalAfter >= toBalBefore + amount);
    47
        }
    48
    
                                                    
                                                
    49
        /**
    50
         * @notice The receiving account's balance after a transfer must not
    51
         * increase by more than the amount transferred
    52
         * @param fromAcc Account to transfer from
    53
         * @param toAcc Account to transfer to
    54
         * @param amount Amount to transfer
    55
         */
    56
        function testTransferBalanceReceivedMore(
    57
            uint8 fromAcc,
    58
            uint8 toAcc,
    59
            uint256 amount
    60
        ) public {
    61
    ✓ 16.7M
            address from = getAccount(fromAcc);
    62
    ✓ 16.7M
            address to = getAccount(toAcc);
    63
    
                                                    
                                                
    64
    ✓ 16.7M
            require(from != to);
    65
    
                                                    
                                                
    66
    ✓ 14.1M
            uint256 toBalBefore = ousd.balanceOf(to);
    67
    ✓ 14.1M
            transfer(fromAcc, toAcc, amount);
    68
    ✓ 553.0K
            uint256 toBalAfter = ousd.balanceOf(to);
    69
    
                                                    
                                                
    70
    ✓ 553.0K
            Debugger.log("totalSupply", ousd.totalSupply());
    71
    ✓ 553.0K
            Debugger.log("toBalBefore", toBalBefore);
    72
    ✓ 553.0K
            Debugger.log("toBalAfter", toBalAfter);
    73
    
                                                    
                                                
    74
    ✓ 553.0K
            assert(toBalAfter <= toBalBefore + amount);
    75
        }
    76
    
                                                    
                                                
    77
        /**
    78
         * @notice The sending account's balance after a transfer must not
    79
         * decrease by less than the amount transferred
    80
         * @param fromAcc Account to transfer from
    81
         * @param toAcc Account to transfer to
    82
         * @param amount Amount to transfer
    83
         * @custom:error testTransferBalanceSentLess(uint8,uint8,uint256): failed!💥
    84
         *   Call sequence:
    85
         *     mint(0,1)
    86
         *     changeSupply(1)
    87
         *     testTransferBalanceSentLess(0,64,1)
    88
         *   Event sequence:
    89
         *     Debug(«totalSupply», 1000000000000000000500001)
    90
         *     Debug(«fromBalBefore», 1)
    91
         *     Debug(«fromBalAfter», 1)
    92
         */
    93
        function testTransferBalanceSentLess(
    94
            uint8 fromAcc,
    95
            uint8 toAcc,
    96
            uint256 amount
    97
        ) public hasKnownIssue hasKnownIssueWithinLimits {
    98
    ✓ 11.0M
            address from = getAccount(fromAcc);
    99
    ✓ 11.0M
            address to = getAccount(toAcc);
    100
    
                                                    
                                                
    101
    ✓ 11.0M
            require(from != to);
    102
    
                                                    
                                                
    103
    ✓ 8.8M
            uint256 fromBalBefore = ousd.balanceOf(from);
    104
    ✓ 8.8M
            transfer(fromAcc, toAcc, amount);
    105
    ✓ 538.6K
            uint256 fromBalAfter = ousd.balanceOf(from);
    106
    
                                                    
                                                
    107
    ✓ 538.6K
            Debugger.log("totalSupply", ousd.totalSupply());
    108
    ✓ 538.6K
            Debugger.log("fromBalBefore", fromBalBefore);
    109
    ✓ 538.6K
            Debugger.log("fromBalAfter", fromBalAfter);
    110
    
                                                    
                                                
    111
    ✓ 1.1M
            assert(fromBalAfter <= fromBalBefore - amount);
    112
        }
    113
    
                                                    
                                                
    114
        /**
    115
         * @notice The sending account's balance after a transfer must not
    116
         * decrease by more than the amount transferred
    117
         * @param fromAcc Account to transfer from
    118
         * @param toAcc Account to transfer to
    119
         * @param amount Amount to transfer
    120
         */
    121
        function testTransferBalanceSentMore(
    122
            uint8 fromAcc,
    123
            uint8 toAcc,
    124
            uint256 amount
    125
        ) public {
    126
    ✓ 19.6M
            address from = getAccount(fromAcc);
    127
    ✓ 19.6M
            address to = getAccount(toAcc);
    128
    
                                                    
                                                
    129
    ✓ 19.6M
            require(from != to);
    130
    
                                                    
                                                
    131
    ✓ 17.1M
            uint256 fromBalBefore = ousd.balanceOf(from);
    132
    ✓ 17.1M
            transfer(fromAcc, toAcc, amount);
    133
    ✓ 514.5K
            uint256 fromBalAfter = ousd.balanceOf(from);
    134
    
                                                    
                                                
    135
    ✓ 514.5K
            Debugger.log("totalSupply", ousd.totalSupply());
    136
    ✓ 514.5K
            Debugger.log("fromBalBefore", fromBalBefore);
    137
    ✓ 514.5K
            Debugger.log("fromBalAfter", fromBalAfter);
    138
    
                                                    
                                                
    139
    ✓ 1.0M
            assert(fromBalAfter >= fromBalBefore - amount);
    140
        }
    141
    
                                                    
                                                
    142
        /**
    143
         * @notice The receiving account's balance after a transfer must not
    144
         * increase by less than the amount transferred (minus rounding error)
    145
         * @param fromAcc Account to transfer from
    146
         * @param toAcc Account to transfer to
    147
         * @param amount Amount to transfer
    148
         */
    149
        function testTransferBalanceReceivedLessRounding(
    150
            uint8 fromAcc,
    151
            uint8 toAcc,
    152
            uint256 amount
    153
        ) public {
    154
    ✓ 19.6M
            address from = getAccount(fromAcc);
    155
    ✓ 19.6M
            address to = getAccount(toAcc);
    156
    
                                                    
                                                
    157
    ✓ 19.6M
            require(from != to);
    158
    
                                                    
                                                
    159
    ✓ 17.4M
            uint256 toBalBefore = ousd.balanceOf(to);
    160
    ✓ 17.4M
            transfer(fromAcc, toAcc, amount);
    161
    ✓ 557.0K
            uint256 toBalAfter = ousd.balanceOf(to);
    162
    
                                                    
                                                
    163
    ✓ 557.0K
            int256 toDelta = int256(toBalAfter) - int256(toBalBefore);
    164
    
                                                    
                                                
    165
            // delta == amount, if no error
    166
            // delta < amount,  if too little is sent
    167
            // delta > amount,  if too much is sent
    168
    ✓ 557.0K
            int256 error = int256(amount) - toDelta;
    169
    
                                                    
                                                
    170
    ✓ 557.0K
            Debugger.log("totalSupply", ousd.totalSupply());
    171
    ✓ 557.0K
            Debugger.log("toBalBefore", toBalBefore);
    172
    ✓ 557.0K
            Debugger.log("toBalAfter", toBalAfter);
    173
    ✓ 557.0K
            Debugger.log("toDelta", toDelta);
    174
    ✓ 1.1M
            Debugger.log("error", error);
    175
    
                                                    
                                                
    176
    ✓ 1.1M
            assert(error >= 0);
    177
    ✓ 1.0M
            assert(error <= int256(TRANSFER_ROUNDING_ERROR));
    178
        }
    179
    
                                                    
                                                
    180
        /**
    181
         * @notice The sending account's balance after a transfer must
    182
         * not decrease by less than the amount transferred (minus rounding error)
    183
         * @param fromAcc Account to transfer from
    184
         * @param toAcc Account to transfer to
    185
         * @param amount Amount to transfer
    186
         */
    187
        function testTransferBalanceSentLessRounding(
    188
            uint8 fromAcc,
    189
            uint8 toAcc,
    190
            uint256 amount
    191
        ) public {
    192
    ✓ 23.5M
            address from = getAccount(fromAcc);
    193
    ✓ 23.5M
            address to = getAccount(toAcc);
    194
    
                                                    
                                                
    195
    ✓ 23.5M
            require(from != to);
    196
    
                                                    
                                                
    197
    ✓ 17.1M
            uint256 fromBalBefore = ousd.balanceOf(from);
    198
    ✓ 17.1M
            transfer(fromAcc, toAcc, amount);
    199
    ✓ 505.8K
            uint256 fromBalAfter = ousd.balanceOf(from);
    200
    
                                                    
                                                
    201
    ✓ 505.8K
            int256 fromDelta = int256(fromBalAfter) - int256(fromBalBefore);
    202
    
                                                    
                                                
    203
            // delta == -amount, if no error
    204
            // delta < -amount,  if too much is sent
    205
            // delta > -amount,  if too little is sent
    206
    ✓ 505.8K
            int256 error = int256(amount) + fromDelta;
    207
    
                                                    
                                                
    208
    ✓ 505.8K
            Debugger.log("totalSupply", ousd.totalSupply());
    209
    ✓ 505.8K
            Debugger.log("fromBalBefore", fromBalBefore);
    210
    ✓ 505.8K
            Debugger.log("fromBalAfter", fromBalAfter);
    211
    ✓ 505.8K
            Debugger.log("fromDelta", fromDelta);
    212
            Debugger.log("error", error);
    213
    
                                                    
                                                
    214
            assert(error >= 0);
    215
            assert(error <= int256(TRANSFER_ROUNDING_ERROR));
    216
        }
    217
    
                                                    
                                                
    218
        /**
    219
         * @notice An account should always be able to successfully transfer
    220
         * an amount within its balance.
    221
         * @param fromAcc Account to transfer from
    222
         * @param toAcc Account to transfer to
    223
         * @param amount Amount to transfer
    224
         * @custom:error testTransferWithinBalanceDoesNotRevert(uint8,uint8,uint8): failed!💥
    225
         *   Call sequence:
    226
         *       mint(0,1)
    227
         *       changeSupply(3)
    228
         *       optOut(0)
    229
         *       testTransferWithinBalanceDoesNotRevert(0,128,2)
    230
         *       optIn(0)
    231
         *       testTransferWithinBalanceDoesNotRevert(128,0,1)
    232
         *   Event sequence:
    233
         *       error Revert Panic(17): SafeMath over-/under-flows
    234
         */
    235
        function testTransferWithinBalanceDoesNotRevert(
    236
            uint8 fromAcc,
    237
            uint8 toAcc,
    238
            uint256 amount
    239
        ) public hasKnownIssue {
    240
    ✓ 19.9M
            address from = getAccount(fromAcc);
    241
    ✓ 19.9M
            address to = getAccount(toAcc);
    242
    
                                                    
                                                
    243
    ✓ 19.9M
            require(amount > 0);
    244
    ✓ 19.6M
            amount = amount % ousd.balanceOf(from);
    245
    
                                                    
                                                
    246
    ✓ 10.6M
            Debugger.log("Total supply", ousd.totalSupply());
    247
    
                                                    
                                                
    248
    ✓ 7.5M
            hevm.prank(from);
    249
            // slither-disable-next-line unchecked-transfer
    250
    ✓ 7.5M
            try ousd.transfer(to, amount) {
    251
    ✓ 204.0M
                assert(true);
    252
            } catch {
    253
    ✓ 15.3M
                assert(false);
    254
            }
    255
        }
    256
    
                                                    
                                                
    257
        /**
    258
         * @notice An account should never be able to successfully transfer
    259
         * an amount greater than their balance.
    260
         * @param fromAcc Account to transfer from
    261
         * @param toAcc Account to transfer to
    262
         * @param amount Amount to transfer
    263
         */
    264
        function testTransferExceedingBalanceReverts(
    265
            uint8 fromAcc,
    266
            uint8 toAcc,
    267
            uint256 amount
    268
        ) public {
    269
    ✓ 15.8M
            address from = getAccount(fromAcc);
    270
    ✓ 15.8M
            address to = getAccount(toAcc);
    271
    
                                                    
                                                
    272
    ✓ 15.8M
            amount = ousd.balanceOf(from) + 1 + amount;
    273
    
                                                    
                                                
    274
    ✓ 15.3M
            hevm.prank(from);
    275
            // slither-disable-next-line unchecked-transfer
    276
    ✓ 15.3M
            try ousd.transfer(to, amount) {
    277
                assert(false);
    278
            } catch {
    279
    ✓ 15.3M
                assert(true);
    280
            }
    281
        }
    282
    
                                                    
                                                
    283
        /**
    284
         * @notice A transfer to the same account should not change that account's balance
    285
         * @param targetAcc Account to transfer to
    286
         * @param amount Amount to transfer
    287
         */
    288
        function testTransferSelf(uint8 targetAcc, uint256 amount) public {
    289
    ✓ 20.0M
            address target = getAccount(targetAcc);
    290
    
                                                    
                                                
    291
    ✓ 20.0M
            uint256 balanceBefore = ousd.balanceOf(target);
    292
    ✓ 20.0M
            transfer(targetAcc, targetAcc, amount);
    293
    ✓ 4.9M
            uint256 balanceAfter = ousd.balanceOf(target);
    294
    
                                                    
                                                
    295
    ✓ 4.9M
            assert(balanceBefore == balanceAfter);
    296
        }
    297
    
                                                    
                                                
    298
        /**
    299
         * @notice Transfers to the zero account revert
    300
         * @param fromAcc Account to transfer from
    301
         * @param amount Amount to transfer
    302
         */
    303
        function testTransferToZeroAddress(uint8 fromAcc, uint256 amount) public {
    304
    ✓ 11.1M
            address from = getAccount(fromAcc);
    305
    
                                                    
                                                
    306
    ✓ 11.1M
            hevm.prank(from);
    307
            // slither-disable-next-line unchecked-transfer
    308
    ✓ 11.1M
            try ousd.transfer(address(0), amount) {
    309
                assert(false);
    310
            } catch {
    311
    ✓ 11.1M
                assert(true);
    312
            }
    313
        }
    314
    }
    315
    
                                                    
                                                
    0.0% contracts/contracts/echidna/IHevm.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    // https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes
    5
    
                                                    
                                                
    6
    interface IHevm {
    7
        function warp(uint256 x) external;
    8
    
                                                    
                                                
    9
        function roll(uint256 x) external;
    10
    
                                                    
                                                
    11
        function store(
    12
            address c,
    13
            bytes32 loc,
    14
            bytes32 val
    15
        ) external;
    16
    
                                                    
                                                
    17
        function load(address c, bytes32 loc) external returns (bytes32 val);
    18
    
                                                    
                                                
    19
        function sign(uint256 sk, bytes32 digest)
    20
            external
    21
            returns (
    22
                uint8 v,
    23
                bytes32 r,
    24
                bytes32 s
    25
            );
    26
    
                                                    
                                                
    27
        function addr(uint256 sk) external returns (address addr);
    28
    
                                                    
                                                
    29
        function ffi(string[] calldata) external returns (bytes memory);
    30
    
                                                    
                                                
    31
        function prank(address sender) external;
    32
    }
    33
    
                                                    
                                                
    100.0% contracts/contracts/echidna/OUSDEchidna.sol
    Lines covered: 4 / 4 (100.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import "../token/OUSD.sol";
    5
    
                                                    
                                                
    6
    contract OUSDEchidna is OUSD {
    7
        constructor() OUSD() {
    8
            // The Yield Delegation rewrite (#2298) left Governable without a
    9
            // constructor, so the governor slot is zero and the harness could
    10
            // never call initialize() (onlyGovernor). Make the deploying harness
    11
            // the governor so the suite is runnable again.
    12
    ✓ 1
            _setGovernor(msg.sender);
    13
        }
    14
    
                                                    
                                                
    15
        function _isNonRebasingAccountEchidna(address _account)
    16
            public
    17
    ✓ 184.6M
            returns (bool)
    18
        {
    19
    ✓ 184.6M
            _autoMigrate(_account);
    20
    ✓ 184.6M
            return alternativeCreditsPerToken[_account] > 0;
    21
        }
    22
    }
    23
    
                                                    
                                                
    35.3% contracts/contracts/governance/Governable.sol
    Lines covered: 6 / 17 (35.3%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    /**
    5
     * @title Base for contracts that are managed by the Origin Protocol's Governor.
    6
     * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change
    7
     *      from owner to governor and renounce methods removed. Does not use
    8
     *      Context.sol like Ownable.sol does for simplification.
    9
     * @author Origin Protocol Inc
    10
     */
    11
    abstract contract Governable {
    12
        // Storage position of the owner and pendingOwner of the contract
    13
        // keccak256("OUSD.governor");
    14
        bytes32 private constant governorPosition =
    15
            0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;
    16
    
                                                    
                                                
    17
        // keccak256("OUSD.pending.governor");
    18
        bytes32 private constant pendingGovernorPosition =
    19
            0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;
    20
    
                                                    
                                                
    21
        // keccak256("OUSD.reentry.status");
    22
        bytes32 private constant reentryStatusPosition =
    23
            0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;
    24
    
                                                    
                                                
    25
        // See OpenZeppelin ReentrancyGuard implementation
    26
        uint256 constant _NOT_ENTERED = 1;
    27
        uint256 constant _ENTERED = 2;
    28
    
                                                    
                                                
    29
        event PendingGovernorshipTransfer(
    30
            address indexed previousGovernor,
    31
            address indexed newGovernor
    32
        );
    33
    
                                                    
                                                
    34
        event GovernorshipTransferred(
    35
            address indexed previousGovernor,
    36
            address indexed newGovernor
    37
        );
    38
    
                                                    
                                                
    39
        /**
    40
         * @notice Returns the address of the current Governor.
    41
         */
    42
        function governor() public view returns (address) {
    43
            return _governor();
    44
        }
    45
    
                                                    
                                                
    46
        /**
    47
         * @dev Returns the address of the current Governor.
    48
         */
    49
        function _governor() internal view returns (address governorOut) {
    50
            bytes32 position = governorPosition;
    51
            // solhint-disable-next-line no-inline-assembly
    52
            assembly {
    53
    ✓ 1
                governorOut := sload(position)
    54
            }
    55
        }
    56
    
                                                    
                                                
    57
        /**
    58
         * @dev Returns the address of the pending Governor.
    59
         */
    60
        function _pendingGovernor()
    61
            internal
    62
            view
    63
            returns (address pendingGovernor)
    64
        {
    65
            bytes32 position = pendingGovernorPosition;
    66
            // solhint-disable-next-line no-inline-assembly
    67
            assembly {
    68
                pendingGovernor := sload(position)
    69
            }
    70
        }
    71
    
                                                    
                                                
    72
        /**
    73
         * @dev Throws if called by any account other than the Governor.
    74
         */
    75
        modifier onlyGovernor() {
    76
    ✓ 1
            require(isGovernor(), "Caller is not the Governor");
    77
            _;
    78
        }
    79
    
                                                    
                                                
    80
        /**
    81
         * @notice Returns true if the caller is the current Governor.
    82
         */
    83
    ✓ 1
        function isGovernor() public view returns (bool) {
    84
    ✓ 1
            return msg.sender == _governor();
    85
        }
    86
    
                                                    
                                                
    87
        function _setGovernor(address newGovernor) internal {
    88
    ✓ 1
            emit GovernorshipTransferred(_governor(), newGovernor);
    89
    
                                                    
                                                
    90
            bytes32 position = governorPosition;
    91
            // solhint-disable-next-line no-inline-assembly
    92
            assembly {
    93
    ✓ 1
                sstore(position, newGovernor)
    94
            }
    95
        }
    96
    
                                                    
                                                
    97
        /**
    98
         * @dev Prevents a contract from calling itself, directly or indirectly.
    99
         * Calling a `nonReentrant` function from another `nonReentrant`
    100
         * function is not supported. It is possible to prevent this from happening
    101
         * by making the `nonReentrant` function external, and make it call a
    102
         * `private` function that does the actual work.
    103
         */
    104
        modifier nonReentrant() {
    105
            bytes32 position = reentryStatusPosition;
    106
            uint256 _reentry_status;
    107
            // solhint-disable-next-line no-inline-assembly
    108
            assembly {
    109
                _reentry_status := sload(position)
    110
            }
    111
    
                                                    
                                                
    112
            // On the first call to nonReentrant, _notEntered will be true
    113
            require(_reentry_status != _ENTERED, "Reentrant call");
    114
    
                                                    
                                                
    115
            // Any calls to nonReentrant after this point will fail
    116
            // solhint-disable-next-line no-inline-assembly
    117
            assembly {
    118
                sstore(position, _ENTERED)
    119
            }
    120
    
                                                    
                                                
    121
            _;
    122
    
                                                    
                                                
    123
            // By storing the original value once again, a refund is triggered (see
    124
            // https://eips.ethereum.org/EIPS/eip-2200)
    125
            // solhint-disable-next-line no-inline-assembly
    126
            assembly {
    127
                sstore(position, _NOT_ENTERED)
    128
            }
    129
        }
    130
    
                                                    
                                                
    131
        function _setPendingGovernor(address newGovernor) internal {
    132
            bytes32 position = pendingGovernorPosition;
    133
            // solhint-disable-next-line no-inline-assembly
    134
            assembly {
    135
                sstore(position, newGovernor)
    136
            }
    137
        }
    138
    
                                                    
                                                
    139
        /**
    140
         * @notice Transfers Governance of the contract to a new account (`newGovernor`).
    141
         * Can only be called by the current Governor. Must be claimed for this to complete
    142
         * @param _newGovernor Address of the new Governor
    143
         */
    144
        function transferGovernance(address _newGovernor) external onlyGovernor {
    145
            _setPendingGovernor(_newGovernor);
    146
            emit PendingGovernorshipTransfer(_governor(), _newGovernor);
    147
        }
    148
    
                                                    
                                                
    149
        /**
    150
         * @notice Claim Governance of the contract to a new account (`newGovernor`).
    151
         * Can only be called by the new Governor.
    152
         */
    153
        function claimGovernance() external {
    154
            require(
    155
                msg.sender == _pendingGovernor(),
    156
                "Only the pending Governor can complete the claim"
    157
            );
    158
            _changeGovernor(msg.sender);
    159
        }
    160
    
                                                    
                                                
    161
        /**
    162
         * @dev Change Governance of the contract to a new account (`newGovernor`).
    163
         * @param _newGovernor Address of the new Governor
    164
         */
    165
        function _changeGovernor(address _newGovernor) internal {
    166
            require(_newGovernor != address(0), "New Governor is address(0)");
    167
            _setGovernor(_newGovernor);
    168
        }
    169
    }
    170
    
                                                    
                                                
    0.0% contracts/contracts/interfaces/IBasicToken.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: MIT
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    interface IBasicToken {
    5
        function symbol() external view returns (string memory);
    6
    
                                                    
                                                
    7
        function decimals() external view returns (uint8);
    8
    }
    9
    
                                                    
                                                
    0.0% contracts/contracts/interfaces/IStrategy.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    /**
    5
     * @title Platform interface to integrate with lending platform like Compound, AAVE etc.
    6
     */
    7
    interface IStrategy {
    8
        /**
    9
         * @dev Deposit the given asset to platform
    10
         * @param _asset asset address
    11
         * @param _amount Amount to deposit
    12
         */
    13
        function deposit(address _asset, uint256 _amount) external;
    14
    
                                                    
                                                
    15
        /**
    16
         * @dev Deposit the entire balance of all supported assets in the Strategy
    17
         *      to the platform
    18
         */
    19
        function depositAll() external;
    20
    
                                                    
                                                
    21
        /**
    22
         * @dev Withdraw given asset from Lending platform
    23
         */
    24
        function withdraw(
    25
            address _recipient,
    26
            address _asset,
    27
            uint256 _amount
    28
        ) external;
    29
    
                                                    
                                                
    30
        /**
    31
         * @dev Liquidate all assets in strategy and return them to Vault.
    32
         */
    33
        function withdrawAll() external;
    34
    
                                                    
                                                
    35
        /**
    36
         * @dev Returns the current balance of the given asset.
    37
         */
    38
        function checkBalance(address _asset)
    39
            external
    40
            view
    41
            returns (uint256 balance);
    42
    
                                                    
                                                
    43
        /**
    44
         * @dev Returns bool indicating whether strategy supports asset.
    45
         */
    46
        function supportsAsset(address _asset) external view returns (bool);
    47
    
                                                    
                                                
    48
        /**
    49
         * @dev Collect reward tokens from the Strategy.
    50
         */
    51
        function collectRewardTokens() external;
    52
    
                                                    
                                                
    53
        /**
    54
         * @dev The address array of the reward tokens for the Strategy.
    55
         */
    56
        function getRewardTokenAddresses() external view returns (address[] memory);
    57
    
                                                    
                                                
    58
        function harvesterAddress() external view returns (address);
    59
    
                                                    
                                                
    60
        function transferToken(address token, uint256 amount) external;
    61
    
                                                    
                                                
    62
        function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)
    63
            external;
    64
    }
    65
    
                                                    
                                                
    0.0% contracts/contracts/interfaces/IVault.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import { VaultStorage } from "../vault/VaultStorage.sol";
    5
    
                                                    
                                                
    6
    interface IVault {
    7
        // slither-disable-start constable-states
    8
    
                                                    
                                                
    9
        event AssetAllocated(address _asset, address _strategy, uint256 _amount);
    10
        event StrategyApproved(address _addr);
    11
        event StrategyRemoved(address _addr);
    12
        event Mint(address _addr, uint256 _value);
    13
        event Redeem(address _addr, uint256 _value);
    14
        event CapitalPaused();
    15
        event CapitalUnpaused();
    16
        event DefaultStrategyUpdated(address _strategy);
    17
        event RebasePaused();
    18
        event RebaseUnpaused();
    19
        event VaultBufferUpdated(uint256 _vaultBuffer);
    20
        event AllocateThresholdUpdated(uint256 _threshold);
    21
        event StrategistUpdated(address _address);
    22
        event MaxSupplyDiffChanged(uint256 maxSupplyDiff);
    23
        event YieldDistribution(address _to, uint256 _yield, uint256 _fee);
    24
        event TrusteeFeeBpsChanged(uint256 _basis);
    25
        event TrusteeAddressChanged(address _address);
    26
        event StrategyAddedToMintWhitelist(address indexed strategy);
    27
        event StrategyRemovedFromMintWhitelist(address indexed strategy);
    28
        event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);
    29
        event DripDurationChanged(uint256 dripDuration);
    30
        event WithdrawalRequested(
    31
            address indexed _withdrawer,
    32
            uint256 indexed _requestId,
    33
            uint256 _amount,
    34
            uint256 _queued
    35
        );
    36
        event WithdrawalClaimed(
    37
            address indexed _withdrawer,
    38
            uint256 indexed _requestId,
    39
            uint256 _amount
    40
        );
    41
        event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);
    42
        event WithdrawalClaimDelayUpdated(uint256 _newDelay);
    43
    
                                                    
                                                
    44
        // Governable.sol
    45
        function transferGovernance(address _newGovernor) external;
    46
    
                                                    
                                                
    47
        function claimGovernance() external;
    48
    
                                                    
                                                
    49
        function governor() external view returns (address);
    50
    
                                                    
                                                
    51
        // VaultAdmin.sol
    52
        function setVaultBuffer(uint256 _vaultBuffer) external;
    53
    
                                                    
                                                
    54
        function vaultBuffer() external view returns (uint256);
    55
    
                                                    
                                                
    56
        function setAutoAllocateThreshold(uint256 _threshold) external;
    57
    
                                                    
                                                
    58
        function autoAllocateThreshold() external view returns (uint256);
    59
    
                                                    
                                                
    60
        function setStrategistAddr(address _address) external;
    61
    
                                                    
                                                
    62
        function strategistAddr() external view returns (address);
    63
    
                                                    
                                                
    64
        function setOperatorAddr(address _operator) external;
    65
    
                                                    
                                                
    66
        function operatorAddr() external view returns (address);
    67
    
                                                    
                                                
    68
        function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;
    69
    
                                                    
                                                
    70
        function maxSupplyDiff() external view returns (uint256);
    71
    
                                                    
                                                
    72
        function setTrusteeAddress(address _address) external;
    73
    
                                                    
                                                
    74
        function trusteeAddress() external view returns (address);
    75
    
                                                    
                                                
    76
        function setTrusteeFeeBps(uint256 _basis) external;
    77
    
                                                    
                                                
    78
        function trusteeFeeBps() external view returns (uint256);
    79
    
                                                    
                                                
    80
        function approveStrategy(address _addr) external;
    81
    
                                                    
                                                
    82
        function removeStrategy(address _addr) external;
    83
    
                                                    
                                                
    84
        function setDefaultStrategy(address _strategy) external;
    85
    
                                                    
                                                
    86
        function defaultStrategy() external view returns (address);
    87
    
                                                    
                                                
    88
        function pauseRebase() external;
    89
    
                                                    
                                                
    90
        function unpauseRebase() external;
    91
    
                                                    
                                                
    92
        function rebasePaused() external view returns (bool);
    93
    
                                                    
                                                
    94
        function pauseCapital() external;
    95
    
                                                    
                                                
    96
        function unpauseCapital() external;
    97
    
                                                    
                                                
    98
        function capitalPaused() external view returns (bool);
    99
    
                                                    
                                                
    100
        function transferToken(address _asset, uint256 _amount) external;
    101
    
                                                    
                                                
    102
        function withdrawAllFromStrategy(address _strategyAddr) external;
    103
    
                                                    
                                                
    104
        function withdrawAllFromStrategies() external;
    105
    
                                                    
                                                
    106
        function withdrawFromStrategy(
    107
            address _strategyFromAddress,
    108
            address[] calldata _assets,
    109
            uint256[] calldata _amounts
    110
        ) external;
    111
    
                                                    
                                                
    112
        function depositToStrategy(
    113
            address _strategyToAddress,
    114
            address[] calldata _assets,
    115
            uint256[] calldata _amounts
    116
        ) external;
    117
    
                                                    
                                                
    118
        // VaultCore.sol
    119
        function mint(uint256 _amount) external;
    120
    
                                                    
                                                
    121
        function mintForStrategy(uint256 _amount) external;
    122
    
                                                    
                                                
    123
        function burnForStrategy(uint256 _amount) external;
    124
    
                                                    
                                                
    125
        function allocate() external;
    126
    
                                                    
                                                
    127
        function rebase() external;
    128
    
                                                    
                                                
    129
        function totalValue() external view returns (uint256 value);
    130
    
                                                    
                                                
    131
        function checkBalance(address _asset) external view returns (uint256);
    132
    
                                                    
                                                
    133
        function getAssetCount() external view returns (uint256);
    134
    
                                                    
                                                
    135
        function getAllAssets() external view returns (address[] memory);
    136
    
                                                    
                                                
    137
        function getStrategyCount() external view returns (uint256);
    138
    
                                                    
                                                
    139
        function getAllStrategies() external view returns (address[] memory);
    140
    
                                                    
                                                
    141
        function strategies(address _addr)
    142
            external
    143
            view
    144
            returns (VaultStorage.Strategy memory);
    145
    
                                                    
                                                
    146
        /// @notice Deprecated: use `asset()` instead.
    147
        function isSupportedAsset(address _asset) external view returns (bool);
    148
    
                                                    
                                                
    149
        function asset() external view returns (address);
    150
    
                                                    
                                                
    151
        function oToken() external view returns (address);
    152
    
                                                    
                                                
    153
        function initialize(address) external;
    154
    
                                                    
                                                
    155
        function addWithdrawalQueueLiquidity() external;
    156
    
                                                    
                                                
    157
        function requestWithdrawal(uint256 _amount)
    158
            external
    159
            returns (uint256 requestId, uint256 queued);
    160
    
                                                    
                                                
    161
        function claimWithdrawal(uint256 requestId)
    162
            external
    163
            returns (uint256 amount);
    164
    
                                                    
                                                
    165
        function claimWithdrawals(uint256[] memory requestIds)
    166
            external
    167
            returns (uint256[] memory amounts, uint256 totalAmount);
    168
    
                                                    
                                                
    169
        function withdrawalQueueMetadata()
    170
            external
    171
            view
    172
            returns (VaultStorage.WithdrawalQueueMetadata memory);
    173
    
                                                    
                                                
    174
        function withdrawalRequests(uint256 requestId)
    175
            external
    176
            view
    177
            returns (VaultStorage.WithdrawalRequest memory);
    178
    
                                                    
                                                
    179
        function addStrategyToMintWhitelist(address strategyAddr) external;
    180
    
                                                    
                                                
    181
        function removeStrategyFromMintWhitelist(address strategyAddr) external;
    182
    
                                                    
                                                
    183
        function isMintWhitelistedStrategy(address strategyAddr)
    184
            external
    185
            view
    186
            returns (bool);
    187
    
                                                    
                                                
    188
        function withdrawalClaimDelay() external view returns (uint256);
    189
    
                                                    
                                                
    190
        function setWithdrawalClaimDelay(uint256 newDelay) external;
    191
    
                                                    
                                                
    192
        function lastRebase() external view returns (uint64);
    193
    
                                                    
                                                
    194
        function dripDuration() external view returns (uint64);
    195
    
                                                    
                                                
    196
        function setDripDuration(uint256 _dripDuration) external;
    197
    
                                                    
                                                
    198
        function rebasePerSecondMax() external view returns (uint64);
    199
    
                                                    
                                                
    200
        function setRebaseRateMax(uint256 yearlyApr) external;
    201
    
                                                    
                                                
    202
        function rebasePerSecondTarget() external view returns (uint64);
    203
    
                                                    
                                                
    204
        function previewYield() external view returns (uint256 yield);
    205
    
                                                    
                                                
    206
        // slither-disable-end constable-states
    207
    }
    208
    
                                                    
                                                
    60.6% contracts/contracts/token/OUSD.sol
    Lines covered: 140 / 231 (60.6%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    /**
    5
     * @title OUSD Token Contract
    6
     * @dev ERC20 compatible contract for OUSD
    7
     * @dev Implements an elastic supply
    8
     * @author Origin Protocol Inc
    9
     */
    10
    import { IVault } from "../interfaces/IVault.sol";
    11
    import { Governable } from "../governance/Governable.sol";
    12
    import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
    13
    
                                                    
                                                
    14
    contract OUSD is Governable {
    15
        using SafeCast for int256;
    16
        using SafeCast for uint256;
    17
    
                                                    
                                                
    18
        /// @dev Event triggered when the supply changes
    19
        /// @param totalSupply Updated token total supply
    20
        /// @param rebasingCredits Updated token rebasing credits
    21
        /// @param rebasingCreditsPerToken Updated token rebasing credits per token
    22
        event TotalSupplyUpdatedHighres(
    23
            uint256 totalSupply,
    24
            uint256 rebasingCredits,
    25
            uint256 rebasingCreditsPerToken
    26
        );
    27
        /// @dev Event triggered when an account opts in for rebasing
    28
        /// @param account Address of the account
    29
        event AccountRebasingEnabled(address account);
    30
        /// @dev Event triggered when an account opts out of rebasing
    31
        /// @param account Address of the account
    32
        event AccountRebasingDisabled(address account);
    33
        /// @dev Emitted when `value` tokens are moved from one account `from` to
    34
        ///      another `to`.
    35
        /// @param from Address of the account tokens are moved from
    36
        /// @param to Address of the account tokens are moved to
    37
        /// @param value Amount of tokens transferred
    38
        event Transfer(address indexed from, address indexed to, uint256 value);
    39
        /// @dev Emitted when the allowance of a `spender` for an `owner` is set by
    40
        ///      a call to {approve}. `value` is the new allowance.
    41
        /// @param owner Address of the owner approving allowance
    42
        /// @param spender Address of the spender allowance is granted to
    43
        /// @param value Amount of tokens spender can transfer
    44
        event Approval(
    45
            address indexed owner,
    46
            address indexed spender,
    47
            uint256 value
    48
        );
    49
        /// @dev Yield resulting from {changeSupply} that a `source` account would
    50
        ///      receive is directed to `target` account.
    51
        /// @param source Address of the source forwarding the yield
    52
        /// @param target Address of the target receiving the yield
    53
        event YieldDelegated(address source, address target);
    54
        /// @dev Yield delegation from `source` account to the `target` account is
    55
        ///      suspended.
    56
        /// @param source Address of the source suspending yield forwarding
    57
        /// @param target Address of the target no longer receiving yield from `source`
    58
        ///        account
    59
        event YieldUndelegated(address source, address target);
    60
    
                                                    
                                                
    61
        enum RebaseOptions {
    62
            NotSet,
    63
            StdNonRebasing,
    64
            StdRebasing,
    65
            YieldDelegationSource,
    66
            YieldDelegationTarget
    67
        }
    68
    
                                                    
                                                
    69
        uint256[154] private _gap; // Slots to align with deployed contract
    70
        uint256 private constant MAX_SUPPLY = type(uint128).max;
    71
        /// @dev The amount of tokens in existence
    72
    ✓ 139.8M
        uint256 public totalSupply;
    73
        mapping(address => mapping(address => uint256)) private allowances;
    74
        /// @dev The vault with privileges to execute {mint}, {burn}
    75
        ///     and {changeSupply}
    76
        address public vaultAddress;
    77
        mapping(address => uint256) internal creditBalances;
    78
        // the 2 storage variables below need trailing underscores to not name collide with public functions
    79
        uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)
    80
        uint256 private rebasingCreditsPerToken_;
    81
        /// @dev The amount of tokens that are not rebasing - receiving yield
    82
    ✓ 27.1M
        uint256 public nonRebasingSupply;
    83
        mapping(address => uint256) internal alternativeCreditsPerToken;
    84
        /// @dev A map of all addresses and their respective RebaseOptions
    85
        mapping(address => RebaseOptions) public rebaseState;
    86
        mapping(address => uint256) private __deprecated_isUpgraded;
    87
        /// @dev A map of addresses that have yields forwarded to. This is an
    88
        ///      inverse mapping of {yieldFrom}
    89
        /// Key Account forwarding yield
    90
        /// Value Account receiving yield
    91
        mapping(address => address) public yieldTo;
    92
        /// @dev A map of addresses that are receiving the yield. This is an
    93
        ///      inverse mapping of {yieldTo}
    94
        /// Key Account receiving yield
    95
        /// Value Account forwarding yield
    96
        mapping(address => address) public yieldFrom;
    97
    
                                                    
                                                
    98
        uint256 private constant RESOLUTION_INCREASE = 1e9;
    99
        uint256[34] private __gap; // including below gap totals up to 200
    100
    
                                                    
                                                
    101
        /// @dev Verifies that the caller is the Governor or Strategist.
    102
        modifier onlyGovernorOrStrategist() {
    103
            require(
    104
                isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),
    105
                "Caller is not the Strategist or Governor"
    106
            );
    107
            _;
    108
        }
    109
    
                                                    
                                                
    110
        /// @dev Initializes the contract and sets necessary variables.
    111
        /// @param _vaultAddress Address of the vault contract
    112
        /// @param _initialCreditsPerToken The starting rebasing credits per token.
    113
        function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)
    114
            external
    115
            onlyGovernor
    116
        {
    117
    ✓ 1
            require(_vaultAddress != address(0), "Zero vault address");
    118
    ✓ 1
            require(vaultAddress == address(0), "Already initialized");
    119
    
                                                    
                                                
    120
    ✓ 1
            rebasingCreditsPerToken_ = _initialCreditsPerToken;
    121
    ✓ 1
            vaultAddress = _vaultAddress;
    122
        }
    123
    
                                                    
                                                
    124
        /// @dev Returns the symbol of the token, a shorter version
    125
        ///      of the name.
    126
        function symbol() external pure virtual returns (string memory) {
    127
            return "OUSD";
    128
        }
    129
    
                                                    
                                                
    130
        /// @dev Returns the name of the token.
    131
        function name() external pure virtual returns (string memory) {
    132
            return "Origin Dollar";
    133
        }
    134
    
                                                    
                                                
    135
        /// @dev Returns the number of decimals used to get its user representation.
    136
        function decimals() external pure virtual returns (uint8) {
    137
            return 18;
    138
        }
    139
    
                                                    
                                                
    140
        /**
    141
         * @dev Verifies that the caller is the Vault contract
    142
         */
    143
        modifier onlyVault() {
    144
    ✓ 69.7M
            require(vaultAddress == msg.sender, "Caller is not the Vault");
    145
    ✓ 1.3B
            _;
    146
        }
    147
    
                                                    
                                                
    148
        /**
    149
         * @return High resolution rebasingCreditsPerToken
    150
         */
    151
        function rebasingCreditsPerTokenHighres() external view returns (uint256) {
    152
    ✓ 26.5M
            return rebasingCreditsPerToken_;
    153
        }
    154
    
                                                    
                                                
    155
        /**
    156
         * @return Low resolution rebasingCreditsPerToken
    157
         */
    158
        function rebasingCreditsPerToken() external view returns (uint256) {
    159
            return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;
    160
        }
    161
    
                                                    
                                                
    162
        /**
    163
         * @return High resolution total number of rebasing credits
    164
         */
    165
        function rebasingCreditsHighres() external view returns (uint256) {
    166
            return rebasingCredits_;
    167
        }
    168
    
                                                    
                                                
    169
        /**
    170
         * @return Low resolution total number of rebasing credits
    171
         */
    172
        function rebasingCredits() external view returns (uint256) {
    173
            return rebasingCredits_ / RESOLUTION_INCREASE;
    174
        }
    175
    
                                                    
                                                
    176
        /**
    177
         * @notice Gets the balance of the specified address.
    178
         * @param _account Address to query the balance of.
    179
         * @return A uint256 representing the amount of base units owned by the
    180
         *         specified address.
    181
         */
    182
    ✓ 957.9M
        function balanceOf(address _account) public view returns (uint256) {
    183
    ✓ 957.9M
            RebaseOptions state = rebaseState[_account];
    184
    ✓ 957.9M
            if (state == RebaseOptions.YieldDelegationSource) {
    185
                // Saves a slot read when transferring to or from a yield delegating source
    186
                // since we know creditBalances equals the balance.
    187
                return creditBalances[_account];
    188
            }
    189
    ✓ 957.9M
            uint256 baseBalance = (creditBalances[_account] * 1e18) /
    190
    ✓ 957.9M
                _creditsPerToken(_account);
    191
    ✓ 957.9M
            if (state == RebaseOptions.YieldDelegationTarget) {
    192
                // creditBalances of yieldFrom accounts equals token balances
    193
                return baseBalance - creditBalances[yieldFrom[_account]];
    194
            }
    195
    ✓ 1.8B
            return baseBalance;
    196
        }
    197
    
                                                    
                                                
    198
        /**
    199
         * @notice Gets the credits balance of the specified address.
    200
         * @dev Backwards compatible with old low res credits per token.
    201
         * @param _account The address to query the balance of.
    202
         * @return (uint256, uint256) Credit balance and credits per token of the
    203
         *         address
    204
         */
    205
        function creditsBalanceOf(address _account)
    206
            external
    207
            view
    208
            returns (uint256, uint256)
    209
        {
    210
            uint256 cpt = _creditsPerToken(_account);
    211
            if (cpt == 1e27) {
    212
                // For a period before the resolution upgrade, we created all new
    213
                // contract accounts at high resolution. Since they are not changing
    214
                // as a result of this upgrade, we will return their true values
    215
                return (creditBalances[_account], cpt);
    216
            } else {
    217
                return (
    218
                    creditBalances[_account] / RESOLUTION_INCREASE,
    219
                    cpt / RESOLUTION_INCREASE
    220
                );
    221
            }
    222
        }
    223
    
                                                    
                                                
    224
        /**
    225
         * @notice Gets the credits balance of the specified address.
    226
         * @param _account The address to query the balance of.
    227
         * @return (uint256, uint256, bool) Credit balance, credits per token of the
    228
         *         address, and isUpgraded
    229
         */
    230
        function creditsBalanceOfHighres(address _account)
    231
            external
    232
            view
    233
            returns (
    234
    ✓ 11.3M
                uint256,
    235
                uint256,
    236
                bool
    237
            )
    238
        {
    239
            return (
    240
    ✓ 11.3M
                creditBalances[_account],
    241
    ✓ 11.3M
                _creditsPerToken(_account),
    242
    ✓ 11.3M
                true // all accounts have their resolution "upgraded"
    243
            );
    244
        }
    245
    
                                                    
                                                
    246
        // Backwards compatible view
    247
        function nonRebasingCreditsPerToken(address _account)
    248
            external
    249
            view
    250
            returns (uint256)
    251
        {
    252
            return alternativeCreditsPerToken[_account];
    253
        }
    254
    
                                                    
                                                
    255
        /**
    256
         * @notice Transfer tokens to a specified address.
    257
         * @param _to the address to transfer to.
    258
         * @param _value the amount to be transferred.
    259
         * @return true on success.
    260
         */
    261
    ✓ 149.9M
        function transfer(address _to, uint256 _value) external returns (bool) {
    262
    ✓ 149.9M
            require(_to != address(0), "Transfer to zero address");
    263
    
                                                    
                                                
    264
    ✓ 138.8M
            _executeTransfer(msg.sender, _to, _value);
    265
    
                                                    
                                                
    266
    ✓ 16.7M
            emit Transfer(msg.sender, _to, _value);
    267
            return true;
    268
        }
    269
    
                                                    
                                                
    270
        /**
    271
         * @notice Transfer tokens from one address to another.
    272
         * @param _from The address you want to send tokens from.
    273
         * @param _to The address you want to transfer to.
    274
         * @param _value The amount of tokens to be transferred.
    275
         * @return true on success.
    276
         */
    277
        function transferFrom(
    278
            address _from,
    279
            address _to,
    280
            uint256 _value
    281
    ✓ 34.9M
        ) external returns (bool) {
    282
    ✓ 34.9M
            require(_to != address(0), "Transfer to zero address");
    283
    ✓ 34.9M
            uint256 userAllowance = allowances[_from][msg.sender];
    284
    ✓ 34.9M
            require(_value <= userAllowance, "Allowance exceeded");
    285
    
                                                    
                                                
    286
            unchecked {
    287
    ✓ 5.3M
                allowances[_from][msg.sender] = userAllowance - _value;
    288
            }
    289
    
                                                    
                                                
    290
    ✓ 5.3M
            _executeTransfer(_from, _to, _value);
    291
    
                                                    
                                                
    292
    ✓ 1.4M
            emit Transfer(_from, _to, _value);
    293
    ✓ 1.4M
            return true;
    294
        }
    295
    
                                                    
                                                
    296
        function _executeTransfer(
    297
            address _from,
    298
            address _to,
    299
            uint256 _value
    300
        ) internal {
    301
            (
    302
    ✓ 144.1M
                int256 fromRebasingCreditsDiff,
    303
    ✓ 144.1M
                int256 fromNonRebasingSupplyDiff
    304
    ✓ 144.1M
            ) = _adjustAccount(_from, -_value.toInt256());
    305
            (
    306
    ✓ 21.3M
                int256 toRebasingCreditsDiff,
    307
    ✓ 21.3M
                int256 toNonRebasingSupplyDiff
    308
    ✓ 21.3M
            ) = _adjustAccount(_to, _value.toInt256());
    309
    
                                                    
                                                
    310
            _adjustGlobals(
    311
    ✓ 18.0M
                fromRebasingCreditsDiff + toRebasingCreditsDiff,
    312
    ✓ 18.0M
                fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff
    313
            );
    314
        }
    315
    
                                                    
                                                
    316
        function _adjustAccount(address _account, int256 _balanceChange)
    317
            internal
    318
    ✓ 185.0M
            returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)
    319
        {
    320
    ✓ 185.0M
            RebaseOptions state = rebaseState[_account];
    321
    ✓ 185.0M
            int256 currentBalance = balanceOf(_account).toInt256();
    322
    ✓ 185.0M
            if (currentBalance + _balanceChange < 0) {
    323
    ✓ 71.2M
                revert("Transfer amount exceeds balance");
    324
            }
    325
    ✓ 113.7M
            uint256 newBalance = (currentBalance + _balanceChange).toUint256();
    326
    
                                                    
                                                
    327
    ✓ 113.7M
            if (state == RebaseOptions.YieldDelegationSource) {
    328
                address target = yieldTo[_account];
    329
                uint256 targetOldBalance = balanceOf(target);
    330
                uint256 targetNewCredits = _balanceToRebasingCredits(
    331
                    targetOldBalance + newBalance
    332
                );
    333
                rebasingCreditsDiff =
    334
                    targetNewCredits.toInt256() -
    335
                    creditBalances[target].toInt256();
    336
    
                                                    
                                                
    337
                creditBalances[_account] = newBalance;
    338
                creditBalances[target] = targetNewCredits;
    339
    ✓ 113.7M
            } else if (state == RebaseOptions.YieldDelegationTarget) {
    340
                uint256 newCredits = _balanceToRebasingCredits(
    341
                    newBalance + creditBalances[yieldFrom[_account]]
    342
                );
    343
                rebasingCreditsDiff =
    344
                    newCredits.toInt256() -
    345
                    creditBalances[_account].toInt256();
    346
                creditBalances[_account] = newCredits;
    347
            } else {
    348
    ✓ 113.7M
                _autoMigrate(_account);
    349
    ✓ 113.7M
                uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[
    350
                    _account
    351
                ];
    352
    ✓ 113.7M
                if (alternativeCreditsPerTokenMem > 0) {
    353
    ✓ 34.7M
                    nonRebasingSupplyDiff = _balanceChange;
    354
    ✓ 34.7M
                    if (alternativeCreditsPerTokenMem != 1e18) {
    355
                        alternativeCreditsPerToken[_account] = 1e18;
    356
                    }
    357
    ✓ 34.7M
                    creditBalances[_account] = newBalance;
    358
                } else {
    359
    ✓ 79.1M
                    uint256 newCredits = _balanceToRebasingCredits(newBalance);
    360
                    rebasingCreditsDiff =
    361
    ✓ 75.1M
                        newCredits.toInt256() -
    362
    ✓ 75.1M
                        creditBalances[_account].toInt256();
    363
    ✓ 75.1M
                    creditBalances[_account] = newCredits;
    364
                }
    365
            }
    366
        }
    367
    
                                                    
                                                
    368
        function _adjustGlobals(
    369
            int256 _rebasingCreditsDiff,
    370
            int256 _nonRebasingSupplyDiff
    371
        ) internal {
    372
    ✓ 175.2M
            if (_rebasingCreditsDiff != 0) {
    373
    ✓ 71.2M
                rebasingCredits_ = (rebasingCredits_.toInt256() +
    374
    ✓ 71.2M
                    _rebasingCreditsDiff).toUint256();
    375
            }
    376
    ✓ 175.2M
            if (_nonRebasingSupplyDiff != 0) {
    377
    ✓ 52.2M
                nonRebasingSupply = (nonRebasingSupply.toInt256() +
    378
    ✓ 52.2M
                    _nonRebasingSupplyDiff).toUint256();
    379
            }
    380
        }
    381
    
                                                    
                                                
    382
        /**
    383
         * @notice Function to check the amount of tokens that _owner has allowed
    384
         *      to `_spender`.
    385
         * @param _owner The address which owns the funds.
    386
         * @param _spender The address which will spend the funds.
    387
         * @return The number of tokens still available for the _spender.
    388
         */
    389
        function allowance(address _owner, address _spender)
    390
            external
    391
            view
    392
    ✓ 28.0M
            returns (uint256)
    393
        {
    394
    ✓ 28.0M
            return allowances[_owner][_spender];
    395
        }
    396
    
                                                    
                                                
    397
        /**
    398
         * @notice Approve the passed address to spend the specified amount of
    399
         *      tokens on behalf of msg.sender.
    400
         * @param _spender The address which will spend the funds.
    401
         * @param _value The amount of tokens to be spent.
    402
         * @return true on success.
    403
         */
    404
    ✓ 46.1M
        function approve(address _spender, uint256 _value) external returns (bool) {
    405
    ✓ 46.1M
            allowances[msg.sender][_spender] = _value;
    406
    ✓ 62.8M
            emit Approval(msg.sender, _spender, _value);
    407
    ✓ 62.8M
            return true;
    408
        }
    409
    
                                                    
                                                
    410
        /**
    411
         * @notice Creates `_amount` tokens and assigns them to `_account`,
    412
         *     increasing the total supply.
    413
         */
    414
        function mint(address _account, uint256 _amount) external onlyVault {
    415
    ✓ 55.3M
            require(_account != address(0), "Mint to the zero address");
    416
    
                                                    
                                                
    417
            // Account
    418
            (
    419
    ✓ 55.3M
                int256 toRebasingCreditsDiff,
    420
    ✓ 55.3M
                int256 toNonRebasingSupplyDiff
    421
    ✓ 185.0M
            ) = _adjustAccount(_account, _amount.toInt256());
    422
            // Globals
    423
    ✓ 54.6M
            _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);
    424
    ✓ 54.6M
            totalSupply = totalSupply + _amount;
    425
    
                                                    
                                                
    426
    ✓ 54.6M
            require(totalSupply < MAX_SUPPLY, "Max supply");
    427
    ✓ 54.4M
            emit Transfer(address(0), _account, _amount);
    428
        }
    429
    
                                                    
                                                
    430
        /**
    431
         * @notice Destroys `_amount` tokens from `_account`,
    432
         *     reducing the total supply.
    433
         */
    434
        function burn(address _account, uint256 _amount) external onlyVault {
    435
    ✓ 69.7M
            require(_account != address(0), "Burn from the zero address");
    436
            if (_amount == 0) {
    437
    ✓ 69.7M
                return;
    438
            }
    439
    
                                                    
                                                
    440
            // Account
    441
            (
    442
    ✓ 37.0M
                int256 toRebasingCreditsDiff,
    443
    ✓ 37.0M
                int256 toNonRebasingSupplyDiff
    444
    ✓ 37.0M
            ) = _adjustAccount(_account, -_amount.toInt256());
    445
            // Globals
    446
    ✓ 15.8M
            _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);
    447
    ✓ 15.8M
            totalSupply = totalSupply - _amount;
    448
    
                                                    
                                                
    449
    ✓ 15.8M
            emit Transfer(_account, address(0), _amount);
    450
        }
    451
    
                                                    
                                                
    452
        /**
    453
         * @dev Get the credits per token for an account. Returns a fixed amount
    454
         *      if the account is non-rebasing.
    455
         * @param _account Address of the account.
    456
         */
    457
        function _creditsPerToken(address _account)
    458
            internal
    459
            view
    460
    ✓ 969.3M
            returns (uint256)
    461
        {
    462
    ✓ 969.3M
            uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[
    463
                _account
    464
            ];
    465
    ✓ 969.3M
            if (alternativeCreditsPerTokenMem != 0) {
    466
    ✓ 419.4M
                return alternativeCreditsPerTokenMem;
    467
            } else {
    468
    ✓ 549.8M
                return rebasingCreditsPerToken_;
    469
            }
    470
        }
    471
    
                                                    
                                                
    472
        /**
    473
         * @dev Auto migrate contracts to be non rebasing,
    474
         *     unless they have opted into yield.
    475
         * @param _account Address of the account.
    476
         */
    477
        function _autoMigrate(address _account) internal {
    478
    ✓ 298.4M
            uint256 codeLen = _account.code.length;
    479
    ✓ 298.4M
            bool isEOA = (codeLen == 0) ||
    480
    ✓ 115.7M
                (codeLen == 23 && bytes3(_account.code) == 0xef0100);
    481
            // In previous code versions, contracts would not have had their
    482
            // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated
    483
            // therefore we check the actual accounting used on the account as well.
    484
            if (
    485
    ✓ 298.4M
                (!isEOA) &&
    486
    ✓ 115.7M
                rebaseState[_account] == RebaseOptions.NotSet &&
    487
    ✓ 8.8M
                alternativeCreditsPerToken[_account] == 0
    488
            ) {
    489
    ✓ 8.8M
                _rebaseOptOut(_account);
    490
            }
    491
        }
    492
    
                                                    
                                                
    493
        /**
    494
         * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and
    495
         *      also balance that corresponds to those credits. The latter is important
    496
         *      when adjusting the contract's global nonRebasingSupply to circumvent any
    497
         *      possible rounding errors.
    498
         *
    499
         * @param _balance Balance of the account.
    500
         */
    501
        function _balanceToRebasingCredits(uint256 _balance)
    502
            internal
    503
            view
    504
    ✓ 119.3M
            returns (uint256 rebasingCredits)
    505
        {
    506
            // Rounds up, because we need to ensure that accounts always have
    507
            // at least the balance that they should have.
    508
            // Note this should always be used on an absolute account value,
    509
            // not on a possibly negative diff, because then the rounding would be wrong.
    510
    ✓ 119.3M
            return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;
    511
        }
    512
    
                                                    
                                                
    513
        /**
    514
         * @notice The calling account will start receiving yield after a successful call.
    515
         * @param _account Address of the account.
    516
         */
    517
        function governanceRebaseOptIn(address _account) external onlyGovernor {
    518
            require(_account != address(0), "Zero address not allowed");
    519
            _rebaseOptIn(_account);
    520
        }
    521
    
                                                    
                                                
    522
        /**
    523
         * @notice The calling account will start receiving yield after a successful call.
    524
         */
    525
        function rebaseOptIn() external {
    526
    ✓ 74.2M
            _rebaseOptIn(msg.sender);
    527
        }
    528
    
                                                    
                                                
    529
        function _rebaseOptIn(address _account) internal {
    530
    ✓ 74.2M
            uint256 balance = balanceOf(_account);
    531
    
                                                    
                                                
    532
            // prettier-ignore
    533
            require(
    534
    ✓ 74.2M
                alternativeCreditsPerToken[_account] > 0 ||
    535
                    // Accounts may explicitly `rebaseOptIn` regardless of
    536
                    // accounting if they have a 0 balance.
    537
    ✓ 37.8M
                    creditBalances[_account] == 0
    538
                ,
    539
                "Account must be non-rebasing"
    540
            );
    541
    ✓ 58.2M
            RebaseOptions state = rebaseState[_account];
    542
            // prettier-ignore
    543
            require(
    544
    ✓ 58.2M
                state == RebaseOptions.StdNonRebasing ||
    545
    ✓ 21.8M
                    state == RebaseOptions.NotSet,
    546
                "Only standard non-rebasing accounts can opt in"
    547
            );
    548
    
                                                    
                                                
    549
    ✓ 40.2M
            uint256 newCredits = _balanceToRebasingCredits(balance);
    550
    
                                                    
                                                
    551
            // Account
    552
    ✓ 40.2M
            rebaseState[_account] = RebaseOptions.StdRebasing;
    553
    ✓ 40.2M
            alternativeCreditsPerToken[_account] = 0;
    554
    ✓ 40.2M
            creditBalances[_account] = newCredits;
    555
            // Globals
    556
    ✓ 40.2M
            _adjustGlobals(newCredits.toInt256(), -balance.toInt256());
    557
    
                                                    
                                                
    558
    ✓ 40.2M
            emit AccountRebasingEnabled(_account);
    559
        }
    560
    
                                                    
                                                
    561
        /**
    562
         * @notice The calling account will no longer receive yield
    563
         */
    564
        function rebaseOptOut() external {
    565
    ✓ 72.7M
            _rebaseOptOut(msg.sender);
    566
        }
    567
    
                                                    
                                                
    568
        function _rebaseOptOut(address _account) internal {
    569
            require(
    570
    ✓ 81.6M
                alternativeCreditsPerToken[_account] == 0,
    571
                "Account must be rebasing"
    572
            );
    573
    ✓ 46.6M
            RebaseOptions state = rebaseState[_account];
    574
            require(
    575
    ✓ 46.6M
                state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,
    576
                "Only standard rebasing accounts can opt out"
    577
            );
    578
    
                                                    
                                                
    579
    ✓ 46.6M
            uint256 oldCredits = creditBalances[_account];
    580
    ✓ 46.6M
            uint256 balance = balanceOf(_account);
    581
    
                                                    
                                                
    582
            // Account
    583
    ✓ 46.6M
            rebaseState[_account] = RebaseOptions.StdNonRebasing;
    584
    ✓ 46.6M
            alternativeCreditsPerToken[_account] = 1e18;
    585
    ✓ 46.6M
            creditBalances[_account] = balance;
    586
            // Globals
    587
    ✓ 46.6M
            _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());
    588
    
                                                    
                                                
    589
    ✓ 86.8M
            emit AccountRebasingDisabled(_account);
    590
        }
    591
    
                                                    
                                                
    592
        /**
    593
         * @notice Distribute yield to users. This changes the exchange rate
    594
         *  between "credits" and OUSD tokens to change rebasing user's balances.
    595
         * @param _newTotalSupply New total supply of OUSD.
    596
         */
    597
        function changeSupply(uint256 _newTotalSupply) external onlyVault {
    598
    ✓ 31.3M
            require(totalSupply > 0, "Cannot increase 0 supply");
    599
    
                                                    
                                                
    600
    ✓ 31.3M
            if (totalSupply == _newTotalSupply) {
    601
                emit TotalSupplyUpdatedHighres(
    602
    ✓ 285.4K
                    totalSupply,
    603
    ✓ 285.4K
                    rebasingCredits_,
    604
    ✓ 285.4K
                    rebasingCreditsPerToken_
    605
                );
    606
                return;
    607
            }
    608
    
                                                    
                                                
    609
    ✓ 31.0M
            totalSupply = _newTotalSupply > MAX_SUPPLY
    610
                ? MAX_SUPPLY
    611
    ✓ 21.4M
                : _newTotalSupply;
    612
    
                                                    
                                                
    613
    ✓ 31.0M
            uint256 rebasingSupply = totalSupply - nonRebasingSupply;
    614
            // round up in the favour of the protocol
    615
    ✓ 25.8M
            rebasingCreditsPerToken_ =
    616
    ✓ 29.5M
                (rebasingCredits_ * 1e18 + rebasingSupply - 1) /
    617
    ✓ 29.5M
                rebasingSupply;
    618
    
                                                    
                                                
    619
    ✓ 25.8M
            require(rebasingCreditsPerToken_ > 0, "Invalid change in supply");
    620
    
                                                    
                                                
    621
            emit TotalSupplyUpdatedHighres(
    622
    ✓ 25.8M
                totalSupply,
    623
    ✓ 25.8M
                rebasingCredits_,
    624
    ✓ 25.8M
                rebasingCreditsPerToken_
    625
            );
    626
        }
    627
    
                                                    
                                                
    628
        /*
    629
         * @notice Send the yield from one account to another account.
    630
         *         Each account keeps its own balances.
    631
         */
    632
        function delegateYield(address _from, address _to)
    633
            external
    634
            onlyGovernorOrStrategist
    635
        {
    636
            require(_from != address(0), "Zero from address not allowed");
    637
            require(_to != address(0), "Zero to address not allowed");
    638
    
                                                    
                                                
    639
            require(_from != _to, "Cannot delegate to self");
    640
            require(
    641
                yieldFrom[_to] == address(0) &&
    642
                    yieldTo[_to] == address(0) &&
    643
                    yieldFrom[_from] == address(0) &&
    644
                    yieldTo[_from] == address(0),
    645
                "Blocked by existing yield delegation"
    646
            );
    647
            RebaseOptions stateFrom = rebaseState[_from];
    648
            RebaseOptions stateTo = rebaseState[_to];
    649
    
                                                    
                                                
    650
            require(
    651
                stateFrom == RebaseOptions.NotSet ||
    652
                    stateFrom == RebaseOptions.StdNonRebasing ||
    653
                    stateFrom == RebaseOptions.StdRebasing,
    654
                "Invalid rebaseState from"
    655
            );
    656
    
                                                    
                                                
    657
            require(
    658
                stateTo == RebaseOptions.NotSet ||
    659
                    stateTo == RebaseOptions.StdNonRebasing ||
    660
                    stateTo == RebaseOptions.StdRebasing,
    661
                "Invalid rebaseState to"
    662
            );
    663
    
                                                    
                                                
    664
            if (alternativeCreditsPerToken[_from] == 0) {
    665
                _rebaseOptOut(_from);
    666
            }
    667
            if (alternativeCreditsPerToken[_to] > 0) {
    668
                _rebaseOptIn(_to);
    669
            }
    670
    
                                                    
                                                
    671
            uint256 fromBalance = balanceOf(_from);
    672
            uint256 toBalance = balanceOf(_to);
    673
            uint256 oldToCredits = creditBalances[_to];
    674
            uint256 newToCredits = _balanceToRebasingCredits(
    675
                fromBalance + toBalance
    676
            );
    677
    
                                                    
                                                
    678
            // Set up the bidirectional links
    679
            yieldTo[_from] = _to;
    680
            yieldFrom[_to] = _from;
    681
    
                                                    
                                                
    682
            // Local
    683
            rebaseState[_from] = RebaseOptions.YieldDelegationSource;
    684
            alternativeCreditsPerToken[_from] = 1e18;
    685
            creditBalances[_from] = fromBalance;
    686
            rebaseState[_to] = RebaseOptions.YieldDelegationTarget;
    687
            creditBalances[_to] = newToCredits;
    688
    
                                                    
                                                
    689
            // Global
    690
            int256 creditsChange = newToCredits.toInt256() -
    691
                oldToCredits.toInt256();
    692
            _adjustGlobals(creditsChange, -(fromBalance).toInt256());
    693
            emit YieldDelegated(_from, _to);
    694
        }
    695
    
                                                    
                                                
    696
        /*
    697
         * @notice Stop sending the yield from one account to another account.
    698
         */
    699
        function undelegateYield(address _from) external onlyGovernorOrStrategist {
    700
            // Require a delegation, which will also ensure a valid delegation
    701
            require(yieldTo[_from] != address(0), "Zero address not allowed");
    702
    
                                                    
                                                
    703
            address to = yieldTo[_from];
    704
            uint256 fromBalance = balanceOf(_from);
    705
            uint256 toBalance = balanceOf(to);
    706
            uint256 oldToCredits = creditBalances[to];
    707
            uint256 newToCredits = _balanceToRebasingCredits(toBalance);
    708
    
                                                    
                                                
    709
            // Remove the bidirectional links
    710
            yieldFrom[to] = address(0);
    711
            yieldTo[_from] = address(0);
    712
    
                                                    
                                                
    713
            // Local
    714
            rebaseState[_from] = RebaseOptions.StdNonRebasing;
    715
            // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`
    716
            creditBalances[_from] = fromBalance;
    717
            rebaseState[to] = RebaseOptions.StdRebasing;
    718
            // alternativeCreditsPerToken[to] already 0 from `delegateYield()`
    719
            creditBalances[to] = newToCredits;
    720
    
                                                    
                                                
    721
            // Global
    722
            int256 creditsChange = newToCredits.toInt256() -
    723
                oldToCredits.toInt256();
    724
    ✓ 104.8M
            _adjustGlobals(creditsChange, fromBalance.toInt256());
    725
            emit YieldUndelegated(_from, to);
    726
        }
    727
    }
    728
    
                                                    
                                                
    100.0% contracts/contracts/utils/Helpers.sol
    Lines covered: 1 / 1 (100.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import { IBasicToken } from "../interfaces/IBasicToken.sol";
    5
    
                                                    
                                                
    6
    ✓ 7
    library Helpers {
    7
        /**
    8
         * @notice Fetch the `symbol()` from an ERC20 token
    9
         * @dev Grabs the `symbol()` from a contract
    10
         * @param _token Address of the ERC20 token
    11
         * @return string Symbol of the ERC20 token
    12
         */
    13
        function getSymbol(address _token) internal view returns (string memory) {
    14
            string memory symbol = IBasicToken(_token).symbol();
    15
            return symbol;
    16
        }
    17
    
                                                    
                                                
    18
        /**
    19
         * @notice Fetch the `decimals()` from an ERC20 token
    20
         * @dev Grabs the `decimals()` from a contract and fails if
    21
         *      the decimal value does not live within a certain range
    22
         * @param _token Address of the ERC20 token
    23
         * @return uint256 Decimals of the ERC20 token
    24
         */
    25
        function getDecimals(address _token) internal view returns (uint256) {
    26
            uint256 decimals = IBasicToken(_token).decimals();
    27
            require(
    28
                decimals >= 4 && decimals <= 18,
    29
                "Token must have sufficient decimal places"
    30
            );
    31
    
                                                    
                                                
    32
            return decimals;
    33
        }
    34
    }
    35
    
                                                    
                                                
    0.0% contracts/contracts/utils/Initializable.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    /**
    5
     * @title Base contract any contracts that need to initialize state after deployment.
    6
     * @author Origin Protocol Inc
    7
     */
    8
    abstract contract Initializable {
    9
        /**
    10
         * @dev Indicates that the contract has been initialized.
    11
         */
    12
        bool private initialized;
    13
    
                                                    
                                                
    14
        /**
    15
         * @dev Indicates that the contract is in the process of being initialized.
    16
         */
    17
        bool private initializing;
    18
    
                                                    
                                                
    19
        /**
    20
         * @dev Modifier to protect an initializer function from being invoked twice.
    21
         */
    22
        modifier initializer() {
    23
            require(
    24
                initializing || !initialized,
    25
                "Initializable: contract is already initialized"
    26
            );
    27
    
                                                    
                                                
    28
            bool isTopLevelCall = !initializing;
    29
            if (isTopLevelCall) {
    30
                initializing = true;
    31
                initialized = true;
    32
            }
    33
    
                                                    
                                                
    34
            _;
    35
    
                                                    
                                                
    36
            if (isTopLevelCall) {
    37
                initializing = false;
    38
            }
    39
        }
    40
    
                                                    
                                                
    41
        uint256[50] private ______gap;
    42
    }
    43
    
                                                    
                                                
    100.0% contracts/contracts/utils/StableMath.sol
    Lines covered: 5 / 5 (100.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";
    5
    
                                                    
                                                
    6
    // Based on StableMath from Stability Labs Pty. Ltd.
    7
    // https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol
    8
    
                                                    
                                                
    9
    ✓ 7
    library StableMath {
    10
        using SafeMath for uint256;
    11
    
                                                    
                                                
    12
        /**
    13
         * @dev Scaling unit for use in specific calculations,
    14
         * where 1 * 10**18, or 1e18 represents a unit '1'
    15
         */
    16
    ✓ 11.3M
        uint256 private constant FULL_SCALE = 1e18;
    17
    
                                                    
                                                
    18
        /***************************************
    19
                        Helpers
    20
        ****************************************/
    21
    
                                                    
                                                
    22
        /**
    23
         * @dev Adjust the scale of an integer
    24
         * @param to Decimals to scale to
    25
         * @param from Decimals to scale from
    26
         */
    27
        function scaleBy(
    28
            uint256 x,
    29
            uint256 to,
    30
            uint256 from
    31
        ) internal pure returns (uint256) {
    32
            if (to > from) {
    33
                x = x.mul(10**(to - from));
    34
            } else if (to < from) {
    35
                // slither-disable-next-line divide-before-multiply
    36
                x = x.div(10**(from - to));
    37
            }
    38
            return x;
    39
        }
    40
    
                                                    
                                                
    41
        /***************************************
    42
                   Precise Arithmetic
    43
        ****************************************/
    44
    
                                                    
                                                
    45
        /**
    46
         * @dev Multiplies two precise units, and then truncates by the full scale
    47
         * @param x Left hand input to multiplication
    48
         * @param y Right hand input to multiplication
    49
         * @return Result after multiplying the two inputs and then dividing by the shared
    50
         *         scale unit
    51
         */
    52
        function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {
    53
            return mulTruncateScale(x, y, FULL_SCALE);
    54
        }
    55
    
                                                    
                                                
    56
        /**
    57
         * @dev Multiplies two precise units, and then truncates by the given scale. For example,
    58
         * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18
    59
         * @param x Left hand input to multiplication
    60
         * @param y Right hand input to multiplication
    61
         * @param scale Scale unit
    62
         * @return Result after multiplying the two inputs and then dividing by the shared
    63
         *         scale unit
    64
         */
    65
        function mulTruncateScale(
    66
            uint256 x,
    67
            uint256 y,
    68
            uint256 scale
    69
        ) internal pure returns (uint256) {
    70
            // e.g. assume scale = fullScale
    71
            // z = 10e18 * 9e17 = 9e36
    72
            uint256 z = x.mul(y);
    73
            // return 9e36 / 1e18 = 9e18
    74
            return z.div(scale);
    75
        }
    76
    
                                                    
                                                
    77
        /**
    78
         * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result
    79
         * @param x Left hand input to multiplication
    80
         * @param y Right hand input to multiplication
    81
         * @return Result after multiplying the two inputs and then dividing by the shared
    82
         *          scale unit, rounded up to the closest base unit.
    83
         */
    84
        function mulTruncateCeil(uint256 x, uint256 y)
    85
            internal
    86
            pure
    87
            returns (uint256)
    88
        {
    89
            // e.g. 8e17 * 17268172638 = 138145381104e17
    90
            uint256 scaled = x.mul(y);
    91
            // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17
    92
            uint256 ceil = scaled.add(FULL_SCALE.sub(1));
    93
            // e.g. 13814538111.399...e18 / 1e18 = 13814538111
    94
            return ceil.div(FULL_SCALE);
    95
        }
    96
    
                                                    
                                                
    97
        /**
    98
         * @dev Precisely divides two units, by first scaling the left hand operand. Useful
    99
         *      for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)
    100
         * @param x Left hand input to division
    101
         * @param y Right hand input to division
    102
         * @return Result after multiplying the left operand by the scale, and
    103
         *         executing the division on the right hand input.
    104
         */
    105
        function divPrecisely(uint256 x, uint256 y)
    106
            internal
    107
            pure
    108
    ✓ 11.3M
            returns (uint256)
    109
        {
    110
            // e.g. 8e18 * 1e18 = 8e36
    111
    ✓ 11.3M
            uint256 z = x.mul(FULL_SCALE);
    112
            // e.g. 8e36 / 10e18 = 8e17
    113
    ✓ 11.3M
            return z.div(y);
    114
        }
    115
    }
    116
    
                                                    
                                                
    0.0% contracts/contracts/vault/VaultStorage.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    /**
    5
     * @title OToken VaultStorage contract
    6
     * @notice The VaultStorage contract defines the storage for the Vault contracts
    7
     * @author Origin Protocol Inc
    8
     */
    9
    
                                                    
                                                
    10
    import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    11
    import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
    12
    import { Address } from "@openzeppelin/contracts/utils/Address.sol";
    13
    
                                                    
                                                
    14
    import { IStrategy } from "../interfaces/IStrategy.sol";
    15
    import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
    16
    import { Governable } from "../governance/Governable.sol";
    17
    import { OUSD } from "../token/OUSD.sol";
    18
    import { Initializable } from "../utils/Initializable.sol";
    19
    import "../utils/Helpers.sol";
    20
    
                                                    
                                                
    21
    abstract contract VaultStorage is Initializable, Governable {
    22
        using SafeERC20 for IERC20;
    23
    
                                                    
                                                
    24
        event AssetAllocated(address _asset, address _strategy, uint256 _amount);
    25
        event StrategyApproved(address _addr);
    26
        event StrategyRemoved(address _addr);
    27
        event Mint(address _addr, uint256 _value);
    28
        event Redeem(address _addr, uint256 _value);
    29
        event CapitalPaused();
    30
        event CapitalUnpaused();
    31
        event DefaultStrategyUpdated(address _strategy);
    32
        event RebasePaused();
    33
        event RebaseUnpaused();
    34
        event VaultBufferUpdated(uint256 _vaultBuffer);
    35
        event AllocateThresholdUpdated(uint256 _threshold);
    36
        event StrategistUpdated(address _address);
    37
        event MaxSupplyDiffChanged(uint256 maxSupplyDiff);
    38
        event YieldDistribution(address _to, uint256 _yield, uint256 _fee);
    39
        event TrusteeFeeBpsChanged(uint256 _basis);
    40
        event TrusteeAddressChanged(address _address);
    41
        event StrategyAddedToMintWhitelist(address indexed strategy);
    42
        event StrategyRemovedFromMintWhitelist(address indexed strategy);
    43
        event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);
    44
        event DripDurationChanged(uint256 dripDuration);
    45
        event OperatorUpdated(address newOperator);
    46
        event WithdrawalRequested(
    47
            address indexed _withdrawer,
    48
            uint256 indexed _requestId,
    49
            uint256 _amount,
    50
            uint256 _queued
    51
        );
    52
        event WithdrawalClaimed(
    53
            address indexed _withdrawer,
    54
            uint256 indexed _requestId,
    55
            uint256 _amount
    56
        );
    57
        event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);
    58
        event WithdrawalClaimDelayUpdated(uint256 _newDelay);
    59
    
                                                    
                                                
    60
        // Since we are proxy, all state should be uninitalized.
    61
        // Since this storage contract does not have logic directly on it
    62
        // we should not be checking for to see if these variables can be constant.
    63
        // slither-disable-start uninitialized-state
    64
        // slither-disable-start constable-states
    65
    
                                                    
                                                
    66
        /// @dev mapping of supported vault assets to their configuration
    67
        uint256 private _deprecated_assets;
    68
        /// @dev list of all assets supported by the vault.
    69
        address[] private _deprecated_allAssets;
    70
    
                                                    
                                                
    71
        // Strategies approved for use by the Vault
    72
        struct Strategy {
    73
            bool isSupported;
    74
            uint256 _deprecated; // Deprecated storage slot
    75
        }
    76
        /// @dev mapping of strategy contracts to their configuration
    77
        mapping(address => Strategy) public strategies;
    78
        /// @dev list of all vault strategies
    79
        address[] internal allStrategies;
    80
    
                                                    
                                                
    81
        /// @notice Address of the Oracle price provider contract
    82
        address private _deprecated_priceProvider;
    83
        /// @notice pause rebasing if true
    84
        bool public rebasePaused;
    85
        /// @notice pause operations that change the OToken supply.
    86
        /// eg mint, redeem, allocate, mint/burn for strategy
    87
        bool public capitalPaused;
    88
        /// @notice Redemption fee in basis points. eg 50 = 0.5%
    89
        uint256 private _deprecated_redeemFeeBps;
    90
        /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.
    91
        uint256 public vaultBuffer;
    92
        /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.
    93
        uint256 public autoAllocateThreshold;
    94
        /// @dev Deprecated. Was the auto-rebase trigger threshold for mint/redeem.
    95
        ///      Storage slot retained for proxy compatibility; no longer read or written.
    96
        uint256 internal __deprecatedRebaseThreshold;
    97
    
                                                    
                                                
    98
        /// @dev Address of the OToken token. eg OUSD or OETH.
    99
        OUSD public oToken;
    100
    
                                                    
                                                
    101
        /// @dev Address of the contract responsible for post rebase syncs with AMMs
    102
        address private _deprecated_rebaseHooksAddr = address(0);
    103
    
                                                    
                                                
    104
        /// @dev Deprecated: Address of Uniswap
    105
        address private _deprecated_uniswapAddr = address(0);
    106
    
                                                    
                                                
    107
        /// @notice Address of the Strategist
    108
        address public strategistAddr = address(0);
    109
    
                                                    
                                                
    110
        /// @notice Mapping of asset address to the Strategy that they should automatically
    111
        // be allocated to
    112
        uint256 private _deprecated_assetDefaultStrategies;
    113
    
                                                    
                                                
    114
        /// @notice Max difference between total supply and total value of assets. 18 decimals.
    115
        uint256 public maxSupplyDiff;
    116
    
                                                    
                                                
    117
        /// @notice Trustee contract that can collect a percentage of yield
    118
        address public trusteeAddress;
    119
    
                                                    
                                                
    120
        /// @notice Amount of yield collected in basis points. eg 2000 = 20%
    121
        uint256 public trusteeFeeBps;
    122
    
                                                    
                                                
    123
        /// @dev Deprecated: Tokens that should be swapped for stablecoins
    124
        address[] private _deprecated_swapTokens;
    125
    
                                                    
                                                
    126
        /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral
    127
    
                                                    
                                                
    128
        address private _deprecated_ousdMetaStrategy;
    129
    
                                                    
                                                
    130
        /// @notice How much OTokens are currently minted by the strategy
    131
        int256 private _deprecated_netOusdMintedForStrategy;
    132
    
                                                    
                                                
    133
        /// @notice How much net total OTokens are allowed to be minted by all strategies
    134
        uint256 private _deprecated_netOusdMintForStrategyThreshold;
    135
    
                                                    
                                                
    136
        uint256 private _deprecated_swapConfig;
    137
    
                                                    
                                                
    138
        // List of strategies that can mint oTokens directly
    139
        // Used in OETHBaseVaultCore
    140
        mapping(address => bool) public isMintWhitelistedStrategy;
    141
    
                                                    
                                                
    142
        /// @notice Address of the Dripper contract that streams harvested rewards to the Vault
    143
        /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.
    144
        address private _deprecated_dripper;
    145
    
                                                    
                                                
    146
        /// Withdrawal Queue Storage /////
    147
    
                                                    
                                                
    148
        struct WithdrawalQueueMetadata {
    149
            // cumulative total of all withdrawal requests included the ones that have already been claimed
    150
            uint128 queued;
    151
            // cumulative total of all the requests that can be claimed including the ones that have already been claimed
    152
            uint128 claimable;
    153
            // total of all the requests that have been claimed
    154
            uint128 claimed;
    155
            // index of the next withdrawal request starting at 0
    156
            uint128 nextWithdrawalIndex;
    157
        }
    158
    
                                                    
                                                
    159
        /// @notice Global metadata for the withdrawal queue including:
    160
        /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed
    161
        /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed
    162
        /// claimed - total of all the requests that have been claimed
    163
        /// nextWithdrawalIndex - index of the next withdrawal request starting at 0
    164
        WithdrawalQueueMetadata public withdrawalQueueMetadata;
    165
    
                                                    
                                                
    166
        struct WithdrawalRequest {
    167
            address withdrawer;
    168
            bool claimed;
    169
            uint40 timestamp; // timestamp of the withdrawal request
    170
            // Amount of oTokens to redeem. eg OETH
    171
            uint128 amount;
    172
            // cumulative total of all withdrawal requests including this one.
    173
            // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.
    174
            uint128 queued;
    175
        }
    176
    
                                                    
                                                
    177
        /// @notice Mapping of withdrawal request indices to the user withdrawal request data
    178
        mapping(uint256 => WithdrawalRequest) public withdrawalRequests;
    179
    
                                                    
                                                
    180
        /// @notice Sets a minimum delay that is required to elapse between
    181
        ///     requesting async withdrawals and claiming the request.
    182
        ///     When set to 0 async withdrawals are disabled.
    183
        uint256 public withdrawalClaimDelay;
    184
    
                                                    
                                                
    185
        /// @notice Time in seconds that the vault last rebased yield.
    186
        uint64 public lastRebase;
    187
    
                                                    
                                                
    188
        /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.
    189
        uint64 public dripDuration;
    190
    
                                                    
                                                
    191
        /// @notice max rebase percentage per second
    192
        ///   Can be used to set maximum yield of the protocol,
    193
        ///   spreading out yield over time
    194
        uint64 public rebasePerSecondMax;
    195
    
                                                    
                                                
    196
        /// @notice target rebase rate limit, based on past rates and funds available.
    197
        uint64 public rebasePerSecondTarget;
    198
    
                                                    
                                                
    199
        uint256 internal constant MAX_REBASE = 0.02 ether;
    200
        uint256 internal constant MAX_REBASE_PER_SECOND =
    201
            uint256(0.05 ether) / 1 days;
    202
    
                                                    
                                                
    203
        /// @notice Default strategy for asset
    204
        address public defaultStrategy;
    205
    
                                                    
                                                
    206
        /// @notice Address authorized to call `rebase()` directly. The Governor
    207
        ///         and Strategist are always allowed in addition to this address.
    208
        address public operatorAddr;
    209
    
                                                    
                                                
    210
        // For future use
    211
        uint256[41] private __gap;
    212
    
                                                    
                                                
    213
        /// @notice Index of WETH asset in allAssets array
    214
        /// Legacy OETHVaultCore code, relocated here for vault consistency.
    215
        uint256 private _deprecated_wethAssetIndex;
    216
    
                                                    
                                                
    217
        /// @dev Address of the asset (eg. WETH or USDC)
    218
        address public immutable asset;
    219
        uint8 internal immutable assetDecimals;
    220
    
                                                    
                                                
    221
        // slither-disable-end constable-states
    222
        // slither-disable-end uninitialized-state
    223
    
                                                    
                                                
    224
        constructor(address _asset) {
    225
            uint8 _decimals = IERC20Metadata(_asset).decimals();
    226
            require(_decimals <= 18, "invalid asset decimals");
    227
            asset = _asset;
    228
            assetDecimals = _decimals;
    229
        }
    230
    
                                                    
                                                
    231
        /// @notice Deprecated: use `oToken()` instead.
    232
        function oUSD() external view returns (OUSD) {
    233
            return oToken;
    234
        }
    235
    }
    236
    
                                                    
                                                
    0.0% lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: MIT
    2
    // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)
    3
    
                                                    
                                                
    4
    pragma solidity ^0.8.0;
    5
    
                                                    
                                                
    6
    /**
    7
     * @dev Interface of the ERC20 standard as defined in the EIP.
    8
     */
    9
    interface IERC20 {
    10
        /**
    11
         * @dev Returns the amount of tokens in existence.
    12
         */
    13
        function totalSupply() external view returns (uint256);
    14
    
                                                    
                                                
    15
        /**
    16
         * @dev Returns the amount of tokens owned by `account`.
    17
         */
    18
        function balanceOf(address account) external view returns (uint256);
    19
    
                                                    
                                                
    20
        /**
    21
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
    22
         *
    23
         * Returns a boolean value indicating whether the operation succeeded.
    24
         *
    25
         * Emits a {Transfer} event.
    26
         */
    27
        function transfer(address recipient, uint256 amount) external returns (bool);
    28
    
                                                    
                                                
    29
        /**
    30
         * @dev Returns the remaining number of tokens that `spender` will be
    31
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
    32
         * zero by default.
    33
         *
    34
         * This value changes when {approve} or {transferFrom} are called.
    35
         */
    36
        function allowance(address owner, address spender) external view returns (uint256);
    37
    
                                                    
                                                
    38
        /**
    39
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    40
         *
    41
         * Returns a boolean value indicating whether the operation succeeded.
    42
         *
    43
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
    44
         * that someone may use both the old and the new allowance by unfortunate
    45
         * transaction ordering. One possible solution to mitigate this race
    46
         * condition is to first reduce the spender's allowance to 0 and set the
    47
         * desired value afterwards:
    48
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    49
         *
    50
         * Emits an {Approval} event.
    51
         */
    52
        function approve(address spender, uint256 amount) external returns (bool);
    53
    
                                                    
                                                
    54
        /**
    55
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
    56
         * allowance mechanism. `amount` is then deducted from the caller's
    57
         * allowance.
    58
         *
    59
         * Returns a boolean value indicating whether the operation succeeded.
    60
         *
    61
         * Emits a {Transfer} event.
    62
         */
    63
        function transferFrom(
    64
            address sender,
    65
            address recipient,
    66
            uint256 amount
    67
        ) external returns (bool);
    68
    
                                                    
                                                
    69
        /**
    70
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
    71
         * another (`to`).
    72
         *
    73
         * Note that `value` may be zero.
    74
         */
    75
        event Transfer(address indexed from, address indexed to, uint256 value);
    76
    
                                                    
                                                
    77
        /**
    78
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
    79
         * a call to {approve}. `value` is the new allowance.
    80
         */
    81
        event Approval(address indexed owner, address indexed spender, uint256 value);
    82
    }
    83
    
                                                    
                                                
    0.0% lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol
    Lines covered: 0 / 0 (0.0%)
    1
    // SPDX-License-Identifier: MIT
    2
    // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
    3
    
                                                    
                                                
    4
    pragma solidity ^0.8.0;
    5
    
                                                    
                                                
    6
    import "../IERC20.sol";
    7
    
                                                    
                                                
    8
    /**
    9
     * @dev Interface for the optional metadata functions from the ERC20 standard.
    10
     *
    11
     * _Available since v4.1._
    12
     */
    13
    interface IERC20Metadata is IERC20 {
    14
        /**
    15
         * @dev Returns the name of the token.
    16
         */
    17
        function name() external view returns (string memory);
    18
    
                                                    
                                                
    19
        /**
    20
         * @dev Returns the symbol of the token.
    21
         */
    22
        function symbol() external view returns (string memory);
    23
    
                                                    
                                                
    24
        /**
    25
         * @dev Returns the decimals places of the token.
    26
         */
    27
        function decimals() external view returns (uint8);
    28
    }
    29
    
                                                    
                                                
    100.0% lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol
    Lines covered: 1 / 1 (100.0%)
    1
    // SPDX-License-Identifier: MIT
    2
    // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
    3
    
                                                    
                                                
    4
    pragma solidity ^0.8.0;
    5
    
                                                    
                                                
    6
    import "../IERC20.sol";
    7
    import "../../../utils/Address.sol";
    8
    
                                                    
                                                
    9
    /**
    10
     * @title SafeERC20
    11
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
    12
     * contract returns false). Tokens that return no value (and instead revert or
    13
     * throw on failure) are also supported, non-reverting calls are assumed to be
    14
     * successful.
    15
     * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
    16
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
    17
     */
    18
    ✓ 7
    library SafeERC20 {
    19
        using Address for address;
    20
    
                                                    
                                                
    21
        function safeTransfer(
    22
            IERC20 token,
    23
            address to,
    24
            uint256 value
    25
        ) internal {
    26
            _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    27
        }
    28
    
                                                    
                                                
    29
        function safeTransferFrom(
    30
            IERC20 token,
    31
            address from,
    32
            address to,
    33
            uint256 value
    34
        ) internal {
    35
            _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    36
        }
    37
    
                                                    
                                                
    38
        /**
    39
         * @dev Deprecated. This function has issues similar to the ones found in
    40
         * {IERC20-approve}, and its usage is discouraged.
    41
         *
    42
         * Whenever possible, use {safeIncreaseAllowance} and
    43
         * {safeDecreaseAllowance} instead.
    44
         */
    45
        function safeApprove(
    46
            IERC20 token,
    47
            address spender,
    48
            uint256 value
    49
        ) internal {
    50
            // safeApprove should only be called when setting an initial allowance,
    51
            // or when resetting it to zero. To increase and decrease it, use
    52
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
    53
            require(
    54
                (value == 0) || (token.allowance(address(this), spender) == 0),
    55
                "SafeERC20: approve from non-zero to non-zero allowance"
    56
            );
    57
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    58
        }
    59
    
                                                    
                                                
    60
        function safeIncreaseAllowance(
    61
            IERC20 token,
    62
            address spender,
    63
            uint256 value
    64
        ) internal {
    65
            uint256 newAllowance = token.allowance(address(this), spender) + value;
    66
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    67
        }
    68
    
                                                    
                                                
    69
        function safeDecreaseAllowance(
    70
            IERC20 token,
    71
            address spender,
    72
            uint256 value
    73
        ) internal {
    74
            unchecked {
    75
                uint256 oldAllowance = token.allowance(address(this), spender);
    76
                require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
    77
                uint256 newAllowance = oldAllowance - value;
    78
                _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    79
            }
    80
        }
    81
    
                                                    
                                                
    82
        /**
    83
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
    84
         * on the return value: the return value is optional (but if data is returned, it must not be false).
    85
         * @param token The token targeted by the call.
    86
         * @param data The call data (encoded using abi.encode or one of its variants).
    87
         */
    88
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
    89
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    90
            // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
    91
            // the target address contains contract code and also asserts for success in the low-level call.
    92
    
                                                    
                                                
    93
            bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
    94
            if (returndata.length > 0) {
    95
                // Return data is optional
    96
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    97
            }
    98
        }
    99
    }
    100
    
                                                    
                                                
    100.0% lib/openzeppelin-contracts/contracts/utils/Address.sol
    Lines covered: 1 / 1 (100.0%)
    1
    // SPDX-License-Identifier: MIT
    2
    // OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
    3
    
                                                    
                                                
    4
    pragma solidity ^0.8.0;
    5
    
                                                    
                                                
    6
    /**
    7
     * @dev Collection of functions related to the address type
    8
     */
    9
    ✓ 7
    library Address {
    10
        /**
    11
         * @dev Returns true if `account` is a contract.
    12
         *
    13
         * [IMPORTANT]
    14
         * ====
    15
         * It is unsafe to assume that an address for which this function returns
    16
         * false is an externally-owned account (EOA) and not a contract.
    17
         *
    18
         * Among others, `isContract` will return false for the following
    19
         * types of addresses:
    20
         *
    21
         *  - an externally-owned account
    22
         *  - a contract in construction
    23
         *  - an address where a contract will be created
    24
         *  - an address where a contract lived, but was destroyed
    25
         * ====
    26
         */
    27
        function isContract(address account) internal view returns (bool) {
    28
            // This method relies on extcodesize, which returns 0 for contracts in
    29
            // construction, since the code is only stored at the end of the
    30
            // constructor execution.
    31
    
                                                    
                                                
    32
            uint256 size;
    33
            assembly {
    34
                size := extcodesize(account)
    35
            }
    36
            return size > 0;
    37
        }
    38
    
                                                    
                                                
    39
        /**
    40
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
    41
         * `recipient`, forwarding all available gas and reverting on errors.
    42
         *
    43
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
    44
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
    45
         * imposed by `transfer`, making them unable to receive funds via
    46
         * `transfer`. {sendValue} removes this limitation.
    47
         *
    48
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
    49
         *
    50
         * IMPORTANT: because control is transferred to `recipient`, care must be
    51
         * taken to not create reentrancy vulnerabilities. Consider using
    52
         * {ReentrancyGuard} or the
    53
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
    54
         */
    55
        function sendValue(address payable recipient, uint256 amount) internal {
    56
            require(address(this).balance >= amount, "Address: insufficient balance");
    57
    
                                                    
                                                
    58
            (bool success, ) = recipient.call{value: amount}("");
    59
            require(success, "Address: unable to send value, recipient may have reverted");
    60
        }
    61
    
                                                    
                                                
    62
        /**
    63
         * @dev Performs a Solidity function call using a low level `call`. A
    64
         * plain `call` is an unsafe replacement for a function call: use this
    65
         * function instead.
    66
         *
    67
         * If `target` reverts with a revert reason, it is bubbled up by this
    68
         * function (like regular Solidity function calls).
    69
         *
    70
         * Returns the raw returned data. To convert to the expected return value,
    71
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
    72
         *
    73
         * Requirements:
    74
         *
    75
         * - `target` must be a contract.
    76
         * - calling `target` with `data` must not revert.
    77
         *
    78
         * _Available since v3.1._
    79
         */
    80
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
    81
            return functionCall(target, data, "Address: low-level call failed");
    82
        }
    83
    
                                                    
                                                
    84
        /**
    85
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
    86
         * `errorMessage` as a fallback revert reason when `target` reverts.
    87
         *
    88
         * _Available since v3.1._
    89
         */
    90
        function functionCall(
    91
            address target,
    92
            bytes memory data,
    93
            string memory errorMessage
    94
        ) internal returns (bytes memory) {
    95
            return functionCallWithValue(target, data, 0, errorMessage);
    96
        }
    97
    
                                                    
                                                
    98
        /**
    99
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
    100
         * but also transferring `value` wei to `target`.
    101
         *
    102
         * Requirements:
    103
         *
    104
         * - the calling contract must have an ETH balance of at least `value`.
    105
         * - the called Solidity function must be `payable`.
    106
         *
    107
         * _Available since v3.1._
    108
         */
    109
        function functionCallWithValue(
    110
            address target,
    111
            bytes memory data,
    112
            uint256 value
    113
        ) internal returns (bytes memory) {
    114
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    115
        }
    116
    
                                                    
                                                
    117
        /**
    118
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
    119
         * with `errorMessage` as a fallback revert reason when `target` reverts.
    120
         *
    121
         * _Available since v3.1._
    122
         */
    123
        function functionCallWithValue(
    124
            address target,
    125
            bytes memory data,
    126
            uint256 value,
    127
            string memory errorMessage
    128
        ) internal returns (bytes memory) {
    129
            require(address(this).balance >= value, "Address: insufficient balance for call");
    130
            require(isContract(target), "Address: call to non-contract");
    131
    
                                                    
                                                
    132
            (bool success, bytes memory returndata) = target.call{value: value}(data);
    133
            return verifyCallResult(success, returndata, errorMessage);
    134
        }
    135
    
                                                    
                                                
    136
        /**
    137
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
    138
         * but performing a static call.
    139
         *
    140
         * _Available since v3.3._
    141
         */
    142
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
    143
            return functionStaticCall(target, data, "Address: low-level static call failed");
    144
        }
    145
    
                                                    
                                                
    146
        /**
    147
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
    148
         * but performing a static call.
    149
         *
    150
         * _Available since v3.3._
    151
         */
    152
        function functionStaticCall(
    153
            address target,
    154
            bytes memory data,
    155
            string memory errorMessage
    156
        ) internal view returns (bytes memory) {
    157
            require(isContract(target), "Address: static call to non-contract");
    158
    
                                                    
                                                
    159
            (bool success, bytes memory returndata) = target.staticcall(data);
    160
            return verifyCallResult(success, returndata, errorMessage);
    161
        }
    162
    
                                                    
                                                
    163
        /**
    164
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
    165
         * but performing a delegate call.
    166
         *
    167
         * _Available since v3.4._
    168
         */
    169
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
    170
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    171
        }
    172
    
                                                    
                                                
    173
        /**
    174
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
    175
         * but performing a delegate call.
    176
         *
    177
         * _Available since v3.4._
    178
         */
    179
        function functionDelegateCall(
    180
            address target,
    181
            bytes memory data,
    182
            string memory errorMessage
    183
        ) internal returns (bytes memory) {
    184
            require(isContract(target), "Address: delegate call to non-contract");
    185
    
                                                    
                                                
    186
            (bool success, bytes memory returndata) = target.delegatecall(data);
    187
            return verifyCallResult(success, returndata, errorMessage);
    188
        }
    189
    
                                                    
                                                
    190
        /**
    191
         * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
    192
         * revert reason using the provided one.
    193
         *
    194
         * _Available since v4.3._
    195
         */
    196
        function verifyCallResult(
    197
            bool success,
    198
            bytes memory returndata,
    199
            string memory errorMessage
    200
        ) internal pure returns (bytes memory) {
    201
            if (success) {
    202
                return returndata;
    203
            } else {
    204
                // Look for revert reason and bubble it up if present
    205
                if (returndata.length > 0) {
    206
                    // The easiest way to bubble the revert reason is using memory via assembly
    207
    
                                                    
                                                
    208
                    assembly {
    209
                        let returndata_size := mload(returndata)
    210
                        revert(add(32, returndata), returndata_size)
    211
                    }
    212
                } else {
    213
                    revert(errorMessage);
    214
                }
    215
            }
    216
        }
    217
    }
    218
    
                                                    
                                                
    100.0% lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol
    Lines covered: 6 / 6 (100.0%)
    1
    // SPDX-License-Identifier: MIT
    2
    // OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
    3
    
                                                    
                                                
    4
    pragma solidity ^0.8.0;
    5
    
                                                    
                                                
    6
    /**
    7
     * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
    8
     * checks.
    9
     *
    10
     * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
    11
     * easily result in undesired exploitation or bugs, since developers usually
    12
     * assume that overflows raise errors. `SafeCast` restores this intuition by
    13
     * reverting the transaction when such an operation overflows.
    14
     *
    15
     * Using this library instead of the unchecked operations eliminates an entire
    16
     * class of bugs, so it's recommended to use it always.
    17
     *
    18
     * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
    19
     * all math on `uint256` and `int256` and then downcasting.
    20
     */
    21
    ✓ 7
    library SafeCast {
    22
        /**
    23
         * @dev Returns the downcasted uint224 from uint256, reverting on
    24
         * overflow (when the input is greater than largest uint224).
    25
         *
    26
         * Counterpart to Solidity's `uint224` operator.
    27
         *
    28
         * Requirements:
    29
         *
    30
         * - input must fit into 224 bits
    31
         */
    32
        function toUint224(uint256 value) internal pure returns (uint224) {
    33
            require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
    34
            return uint224(value);
    35
        }
    36
    
                                                    
                                                
    37
        /**
    38
         * @dev Returns the downcasted uint128 from uint256, reverting on
    39
         * overflow (when the input is greater than largest uint128).
    40
         *
    41
         * Counterpart to Solidity's `uint128` operator.
    42
         *
    43
         * Requirements:
    44
         *
    45
         * - input must fit into 128 bits
    46
         */
    47
        function toUint128(uint256 value) internal pure returns (uint128) {
    48
            require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
    49
            return uint128(value);
    50
        }
    51
    
                                                    
                                                
    52
        /**
    53
         * @dev Returns the downcasted uint96 from uint256, reverting on
    54
         * overflow (when the input is greater than largest uint96).
    55
         *
    56
         * Counterpart to Solidity's `uint96` operator.
    57
         *
    58
         * Requirements:
    59
         *
    60
         * - input must fit into 96 bits
    61
         */
    62
        function toUint96(uint256 value) internal pure returns (uint96) {
    63
            require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
    64
            return uint96(value);
    65
        }
    66
    
                                                    
                                                
    67
        /**
    68
         * @dev Returns the downcasted uint64 from uint256, reverting on
    69
         * overflow (when the input is greater than largest uint64).
    70
         *
    71
         * Counterpart to Solidity's `uint64` operator.
    72
         *
    73
         * Requirements:
    74
         *
    75
         * - input must fit into 64 bits
    76
         */
    77
        function toUint64(uint256 value) internal pure returns (uint64) {
    78
            require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
    79
            return uint64(value);
    80
        }
    81
    
                                                    
                                                
    82
        /**
    83
         * @dev Returns the downcasted uint32 from uint256, reverting on
    84
         * overflow (when the input is greater than largest uint32).
    85
         *
    86
         * Counterpart to Solidity's `uint32` operator.
    87
         *
    88
         * Requirements:
    89
         *
    90
         * - input must fit into 32 bits
    91
         */
    92
        function toUint32(uint256 value) internal pure returns (uint32) {
    93
            require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
    94
            return uint32(value);
    95
        }
    96
    
                                                    
                                                
    97
        /**
    98
         * @dev Returns the downcasted uint16 from uint256, reverting on
    99
         * overflow (when the input is greater than largest uint16).
    100
         *
    101
         * Counterpart to Solidity's `uint16` operator.
    102
         *
    103
         * Requirements:
    104
         *
    105
         * - input must fit into 16 bits
    106
         */
    107
        function toUint16(uint256 value) internal pure returns (uint16) {
    108
            require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
    109
            return uint16(value);
    110
        }
    111
    
                                                    
                                                
    112
        /**
    113
         * @dev Returns the downcasted uint8 from uint256, reverting on
    114
         * overflow (when the input is greater than largest uint8).
    115
         *
    116
         * Counterpart to Solidity's `uint8` operator.
    117
         *
    118
         * Requirements:
    119
         *
    120
         * - input must fit into 8 bits.
    121
         */
    122
        function toUint8(uint256 value) internal pure returns (uint8) {
    123
            require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
    124
            return uint8(value);
    125
        }
    126
    
                                                    
                                                
    127
        /**
    128
         * @dev Converts a signed int256 into an unsigned uint256.
    129
         *
    130
         * Requirements:
    131
         *
    132
         * - input must be greater than or equal to 0.
    133
         */
    134
    ✓ 237.2M
        function toUint256(int256 value) internal pure returns (uint256) {
    135
    ✓ 237.2M
            require(value >= 0, "SafeCast: value must be positive");
    136
            return uint256(value);
    137
        }
    138
    
                                                    
                                                
    139
        /**
    140
         * @dev Returns the downcasted int128 from int256, reverting on
    141
         * overflow (when the input is less than smallest int128 or
    142
         * greater than largest int128).
    143
         *
    144
         * Counterpart to Solidity's `int128` operator.
    145
         *
    146
         * Requirements:
    147
         *
    148
         * - input must fit into 128 bits
    149
         *
    150
         * _Available since v3.1._
    151
         */
    152
        function toInt128(int256 value) internal pure returns (int128) {
    153
            require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
    154
            return int128(value);
    155
        }
    156
    
                                                    
                                                
    157
        /**
    158
         * @dev Returns the downcasted int64 from int256, reverting on
    159
         * overflow (when the input is less than smallest int64 or
    160
         * greater than largest int64).
    161
         *
    162
         * Counterpart to Solidity's `int64` operator.
    163
         *
    164
         * Requirements:
    165
         *
    166
         * - input must fit into 64 bits
    167
         *
    168
         * _Available since v3.1._
    169
         */
    170
        function toInt64(int256 value) internal pure returns (int64) {
    171
            require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
    172
            return int64(value);
    173
        }
    174
    
                                                    
                                                
    175
        /**
    176
         * @dev Returns the downcasted int32 from int256, reverting on
    177
         * overflow (when the input is less than smallest int32 or
    178
         * greater than largest int32).
    179
         *
    180
         * Counterpart to Solidity's `int32` operator.
    181
         *
    182
         * Requirements:
    183
         *
    184
         * - input must fit into 32 bits
    185
         *
    186
         * _Available since v3.1._
    187
         */
    188
        function toInt32(int256 value) internal pure returns (int32) {
    189
            require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
    190
            return int32(value);
    191
        }
    192
    
                                                    
                                                
    193
        /**
    194
         * @dev Returns the downcasted int16 from int256, reverting on
    195
         * overflow (when the input is less than smallest int16 or
    196
         * greater than largest int16).
    197
         *
    198
         * Counterpart to Solidity's `int16` operator.
    199
         *
    200
         * Requirements:
    201
         *
    202
         * - input must fit into 16 bits
    203
         *
    204
         * _Available since v3.1._
    205
         */
    206
        function toInt16(int256 value) internal pure returns (int16) {
    207
            require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
    208
            return int16(value);
    209
        }
    210
    
                                                    
                                                
    211
        /**
    212
         * @dev Returns the downcasted int8 from int256, reverting on
    213
         * overflow (when the input is less than smallest int8 or
    214
         * greater than largest int8).
    215
         *
    216
         * Counterpart to Solidity's `int8` operator.
    217
         *
    218
         * Requirements:
    219
         *
    220
         * - input must fit into 8 bits.
    221
         *
    222
         * _Available since v3.1._
    223
         */
    224
        function toInt8(int256 value) internal pure returns (int8) {
    225
            require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
    226
            return int8(value);
    227
        }
    228
    
                                                    
                                                
    229
        /**
    230
         * @dev Converts an unsigned uint256 into a signed int256.
    231
         *
    232
         * Requirements:
    233
         *
    234
         * - input must be less than or equal to maxInt256.
    235
         */
    236
    ✓ 890.0M
        function toInt256(uint256 value) internal pure returns (int256) {
    237
            // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
    238
    ✓ 890.0M
            require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
    239
    ✓ 1.1B
            return int256(value);
    240
        }
    241
    }
    242
    
                                                    
                                                
    100.0% lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol
    Lines covered: 5 / 5 (100.0%)
    1
    // SPDX-License-Identifier: MIT
    2
    // OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)
    3
    
                                                    
                                                
    4
    pragma solidity ^0.8.0;
    5
    
                                                    
                                                
    6
    // CAUTION
    7
    // This version of SafeMath should only be used with Solidity 0.8 or later,
    8
    // because it relies on the compiler's built in overflow checks.
    9
    
                                                    
                                                
    10
    /**
    11
     * @dev Wrappers over Solidity's arithmetic operations.
    12
     *
    13
     * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
    14
     * now has built in overflow checking.
    15
     */
    16
    ✓ 7
    library SafeMath {
    17
        /**
    18
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
    19
         *
    20
         * _Available since v3.4._
    21
         */
    22
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
    23
            unchecked {
    24
                uint256 c = a + b;
    25
                if (c < a) return (false, 0);
    26
                return (true, c);
    27
            }
    28
        }
    29
    
                                                    
                                                
    30
        /**
    31
         * @dev Returns the substraction of two unsigned integers, with an overflow flag.
    32
         *
    33
         * _Available since v3.4._
    34
         */
    35
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
    36
            unchecked {
    37
                if (b > a) return (false, 0);
    38
                return (true, a - b);
    39
            }
    40
        }
    41
    
                                                    
                                                
    42
        /**
    43
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
    44
         *
    45
         * _Available since v3.4._
    46
         */
    47
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
    48
            unchecked {
    49
                // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
    50
                // benefit is lost if 'b' is also tested.
    51
                // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
    52
                if (a == 0) return (true, 0);
    53
                uint256 c = a * b;
    54
                if (c / a != b) return (false, 0);
    55
                return (true, c);
    56
            }
    57
        }
    58
    
                                                    
                                                
    59
        /**
    60
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
    61
         *
    62
         * _Available since v3.4._
    63
         */
    64
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
    65
            unchecked {
    66
                if (b == 0) return (false, 0);
    67
                return (true, a / b);
    68
            }
    69
        }
    70
    
                                                    
                                                
    71
        /**
    72
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
    73
         *
    74
         * _Available since v3.4._
    75
         */
    76
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
    77
            unchecked {
    78
                if (b == 0) return (false, 0);
    79
                return (true, a % b);
    80
            }
    81
        }
    82
    
                                                    
                                                
    83
        /**
    84
         * @dev Returns the addition of two unsigned integers, reverting on
    85
         * overflow.
    86
         *
    87
         * Counterpart to Solidity's `+` operator.
    88
         *
    89
         * Requirements:
    90
         *
    91
         * - Addition cannot overflow.
    92
         */
    93
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
    94
            return a + b;
    95
        }
    96
    
                                                    
                                                
    97
        /**
    98
         * @dev Returns the subtraction of two unsigned integers, reverting on
    99
         * overflow (when the result is negative).
    100
         *
    101
         * Counterpart to Solidity's `-` operator.
    102
         *
    103
         * Requirements:
    104
         *
    105
         * - Subtraction cannot overflow.
    106
         */
    107
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    108
            return a - b;
    109
        }
    110
    
                                                    
                                                
    111
        /**
    112
         * @dev Returns the multiplication of two unsigned integers, reverting on
    113
         * overflow.
    114
         *
    115
         * Counterpart to Solidity's `*` operator.
    116
         *
    117
         * Requirements:
    118
         *
    119
         * - Multiplication cannot overflow.
    120
         */
    121
    ✓ 11.3M
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    122
    ✓ 11.3M
            return a * b;
    123
        }
    124
    
                                                    
                                                
    125
        /**
    126
         * @dev Returns the integer division of two unsigned integers, reverting on
    127
         * division by zero. The result is rounded towards zero.
    128
         *
    129
         * Counterpart to Solidity's `/` operator.
    130
         *
    131
         * Requirements:
    132
         *
    133
         * - The divisor cannot be zero.
    134
         */
    135
    ✓ 11.3M
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
    136
    ✓ 11.3M
            return a / b;
    137
        }
    138
    
                                                    
                                                
    139
        /**
    140
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
    141
         * reverting when dividing by zero.
    142
         *
    143
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
    144
         * opcode (which leaves remaining gas untouched) while Solidity uses an
    145
         * invalid opcode to revert (consuming all remaining gas).
    146
         *
    147
         * Requirements:
    148
         *
    149
         * - The divisor cannot be zero.
    150
         */
    151
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    152
            return a % b;
    153
        }
    154
    
                                                    
                                                
    155
        /**
    156
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
    157
         * overflow (when the result is negative).
    158
         *
    159
         * CAUTION: This function is deprecated because it requires allocating memory for the error
    160
         * message unnecessarily. For custom revert reasons use {trySub}.
    161
         *
    162
         * Counterpart to Solidity's `-` operator.
    163
         *
    164
         * Requirements:
    165
         *
    166
         * - Subtraction cannot overflow.
    167
         */
    168
        function sub(
    169
            uint256 a,
    170
            uint256 b,
    171
            string memory errorMessage
    172
        ) internal pure returns (uint256) {
    173
            unchecked {
    174
                require(b <= a, errorMessage);
    175
                return a - b;
    176
            }
    177
        }
    178
    
                                                    
                                                
    179
        /**
    180
         * @dev Returns the integer division of two unsigned integers, reverting with custom message on
    181
         * division by zero. The result is rounded towards zero.
    182
         *
    183
         * Counterpart to Solidity's `/` operator. Note: this function uses a
    184
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
    185
         * uses an invalid opcode to revert (consuming all remaining gas).
    186
         *
    187
         * Requirements:
    188
         *
    189
         * - The divisor cannot be zero.
    190
         */
    191
        function div(
    192
            uint256 a,
    193
            uint256 b,
    194
            string memory errorMessage
    195
        ) internal pure returns (uint256) {
    196
            unchecked {
    197
                require(b > 0, errorMessage);
    198
                return a / b;
    199
            }
    200
        }
    201
    
                                                    
                                                
    202
        /**
    203
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
    204
         * reverting with custom message when dividing by zero.
    205
         *
    206
         * CAUTION: This function is deprecated because it requires allocating memory for the error
    207
         * message unnecessarily. For custom revert reasons use {tryMod}.
    208
         *
    209
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
    210
         * opcode (which leaves remaining gas untouched) while Solidity uses an
    211
         * invalid opcode to revert (consuming all remaining gas).
    212
         *
    213
         * Requirements:
    214
         *
    215
         * - The divisor cannot be zero.
    216
         */
    217
        function mod(
    218
            uint256 a,
    219
            uint256 b,
    220
            string memory errorMessage
    221
        ) internal pure returns (uint256) {
    222
            unchecked {
    223
                require(b > 0, errorMessage);
    224
                return a % b;
    225
            }
    226
        }
    227
    }
    228
    
                                                    
                                                
    100.0% test/recon/CryticTester.sol
    Lines covered: 1 / 1 (100.0%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import {Properties} from "./Properties.sol";
    5
    
                                                    
                                                
    6
    // echidna test/recon/CryticTester.sol --contract CryticTester --config echidna.yaml
    7
    ✓ 722.1M
    contract CryticTester is Properties {}
    8
    
                                                    
                                                
    57.1% test/recon/Properties.sol
    Lines covered: 4 / 7 (57.1%)
    1
    // SPDX-License-Identifier: BUSL-1.1
    2
    pragma solidity ^0.8.0;
    3
    
                                                    
                                                
    4
    import {Echidna} from "../../contracts/contracts/echidna/Echidna.sol";
    5
    
                                                    
                                                
    6
    /// @notice scfuzzbench adaptation layer: canary checks on top of the
    7
    /// upstream OUSD Echidna suite. Assertion failures are surfaced the same
    8
    /// way for Echidna, Medusa, Foundry, and Recon (AssertionFailed event +
    9
    /// assert), and dedup to the emitting function name across fuzzers.
    10
    abstract contract Properties is Echidna {
    11
        string internal constant ASSERTION_CANARY = "!!! canary assertion";
    12
        string internal constant INVARIANT_CANARY_GLOBAL_INVARIANT_FAILURE = "Canary invariant";
    13
    
                                                    
                                                
    14
        event AssertionFailed(string reason);
    15
    
                                                    
                                                
    16
        function t(bool b, string memory reason) internal {
    17
    ✓ 11.6M
            if (!b) {
    18
    ✓ 252.0K
                emit AssertionFailed(reason);
    19
    ✓ 252.0K
                assert(false);
    20
            }
    21
        }
    22
    
                                                    
                                                
    23
        function invariant_canary() public returns (bool) {
    24
            t(false, INVARIANT_CANARY_GLOBAL_INVARIANT_FAILURE);
    25
            return true;
    26
        }
    27
    
                                                    
                                                
    28
        function assert_canary_ASSERTION_CANARY(uint256 entropy) public {
    29
    ✓ 11.6M
            t(entropy > 0, ASSERTION_CANARY);
    30
        }
    31
    }
    32