Contract 0x356f621A437556C455932fb5507ab3F3af356146

Contract Overview

Balance:
79.374605514814002543 GLMR

GLMR Value:
$35.19 (@ $0.44/GLMR)
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x082318233c0cd743e8fba8ac7d5809e49cb6eda7725858cad928608d80edac36Redeem15806002022-08-04 10:18:1257 days 9 hrs ago0x7e1e1c5ac70038a9718431c92a618f01f8dada18 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.009962022
0xf1218ea0633e8c9e21e874ccd7aec815cfb175718bfbec78a89e31ba5c0ae078Borrow15669992022-08-02 10:40:2459 days 9 hrs ago0x350a2a378a4763ebccfa9eabf59ccc9cc71cec11 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0338038645
0xb01eb1f0eee88dba08f3b9d492e9fff2aff016f27c679b808672fdf154fd7338Redeem15281422022-07-27 17:44:2465 days 2 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0206518
0x98f58aa5054083a3eb575776216c39f91b81b59594ae208cdc5e3c1762090489Redeem Underlyin...15281202022-07-27 17:39:0065 days 2 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0234333
0xe6c4c4ce969b4f15d91f06e181f08c102620dcf181f925d1028ebdfb673b88ecRedeem Underlyin...13243722022-06-27 19:15:0095 days 57 mins ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0234333
0xf328800172d144330ed0b934f37061548e914b99bc6d04d9e75c70e7c7994105Redeem Underlyin...13243652022-06-27 19:13:3695 days 59 mins ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0234333
0x6d86df6b508c0dfc9d20355dfe1ac301fc09be13a39fd223c0de5cd441ebc2e2Redeem Underlyin...13011582022-06-24 8:15:0098 days 11 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0237294
0xd310ef64af0c1132620bd70655d277836529d88d32a8b17481adc8df90a70dacMint13011512022-06-24 8:13:2498 days 11 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af356146700 GLMR0.0115546
0x737e7076ae78b11dc3bacd17668fae404f7c8f1241b03bcfdeb299aa5e7aa1e2Redeem Underlyin...13011382022-06-24 8:10:4898 days 12 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0237294
0xdbf1b7209de6c39ade5c2f6cfc6220b5ce0fc880f77e52ac3e3a7aeea26a303fRedeem Underlyin...13011312022-06-24 8:09:1898 days 12 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.04033998
0x718f177080dfb1f5b4c964a2f82a1157ce04568c824d9d8a68e6baee5cdf4ad4Redeem Underlyin...13011152022-06-24 8:05:5498 days 12 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.03983661
0x02812e707ac340784f2ab1e7429240ee65d2c9a430ac15566a3e4c5ce38ed537Redeem Underlyin...13009672022-06-24 7:34:2498 days 12 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.03983457
0x958b32cd8ff1e47d574074d7cca40600703a50ece2c068d33b7682b7eea878a2Redeem Underlyin...13009582022-06-24 7:32:3098 days 12 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0234333
0x1a6ad3682ab296cdd819fe4c365c86346abd25628bb35d7146535c2fb00128edRedeem Underlyin...13009462022-06-24 7:29:4898 days 12 hrs ago0x362627a677a0a82261bfc3cc6c2df30f032c29c0 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.0234333
0x66883339950a4eb0098655df7dcba485c11699e130b0a0643df42a4e4ef3cad4Borrow12933552022-06-23 4:08:1899 days 16 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.16763142
0x1c8310794cd840269a86636a96ef671c513827d9762ad61c5863591b72b33156Borrow12915072022-06-22 21:34:3699 days 22 hrs ago0x1cb3c6b77fde279cf7403a5c0ae2d5fc9d356a55 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.023101603
0xf06919ebd91c43a1690ab26ff8ab3597123924f6a0cb4e828053771c413e7086Borrow12912662022-06-22 20:44:0699 days 23 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
0x03fe29e8e33885c4239a7a9f576a7861cf80fc48f3bc16781bfa52cd6c474b41Borrow12900032022-06-22 16:08:18100 days 4 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.15534948
0xbe595cd57bccbd3c383479f65b8330ad2967cb03ae515e94b6c4cc677ed535d4Borrow12899672022-06-22 16:00:36100 days 4 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
0x803e081f0a999655f8c970887d386e989c54e2ef2b4589374ea70a5f3062e9b9Borrow12896322022-06-22 14:46:36100 days 5 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
0x96c75d326a1ef8d934abb5a598f6004d737cc537b55806accb349ee10e47f9c6Borrow12871402022-06-22 5:54:54100 days 14 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
0x4fe14163e8a30b5ac21d33cfd75399a48832a39ff281616ba1116701c3d8c81aBorrow12841392022-06-21 19:14:06101 days 58 mins ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
0xaee5bae2456f366ed4888f55089c358a4407ca84fcadf9b18ce200d5bbe513e0Borrow12837122022-06-21 17:43:06101 days 2 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
0xc5290aaae143baa8e205c1c2453598688de9f1d9081c575a29631ad3ba924425Borrow12812062022-06-21 8:42:36101 days 11 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
0xebd19fd9f5a655dad5712b86f8372fb879d2cca9810f6524e0da6f74a7278ed9Borrow12807852022-06-21 7:12:42101 days 12 hrs ago0xa5d20094cf1bc45b6ff1eb3b5a828865c1e8d583 IN  0x356f621a437556c455932fb5507ab3f3af3561460 GLMR0.1553574
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xfc73331ea735c9d21301129fcb1ec1c74734a1d87222bcb7e2e34ecc27988c0715670102022-08-02 10:42:5459 days 9 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614667.00090058293305469 GLMR
0xbc5ead73832b438d603256c8363e800331cd0b6142e72376118f0da14c987e2514232212022-07-12 8:20:0080 days 11 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af3561463,234.254483370223528904 GLMR
0xd47232f1844eafde49da522569669c70116c5c0e6e3b37210e952f4a44a3a26c13045212022-06-24 20:13:5497 days 23 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af356146601.140886608460979327 GLMR
0x660b4b56e12e94d31dd4d4b6ee0df427fd8e7d9b88f5a6a66bd37d171574964c12981232022-06-23 21:21:1898 days 22 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af356146150.800000000000011369 GLMR
0xad195e0d0bb27408e42c34b56d197791ecfd41abf1b1c5565e9233cf745fbc5412980932022-06-23 21:14:5498 days 22 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af3561463,850 GLMR
0x526e236b1d1514bf3738333d123d0d20df740ffe5918c3441129c2867ce7936e12933612022-06-23 4:09:3099 days 16 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614620,000.009039215599186628 GLMR
0x065d21ee3a4c56e532fa81195cec15cb9c0d34a8bb6b27bec077b53e4cf5fb9212918972022-06-22 22:58:4299 days 21 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614610,000.345233437041236204 GLMR
0x07a2ba7022d916ac69cb08e40ae22a6a2bd1ad87d3ae1e8900c55b90645f5eb412908302022-06-22 19:09:06100 days 1 hr ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af3561467,526.659999999999854481 GLMR
0xb67d496ed8ce38a4bb620e79c414465c7cc23b4853c9a47661ee37b38ba6443312907992022-06-22 19:02:18100 days 1 hr ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614616,476 GLMR
0xf56afb0ac8e83c98357c81166e2e306f68e10837a3a852ec4880ad5da13e209512872952022-06-22 6:28:36100 days 13 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614610,023 GLMR
0x62815c4fb05e205dfd852ed251f96c557452578e1d37b714482807ba320c914612845642022-06-21 20:45:00100 days 23 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614621,980 GLMR
0x3c4224ec1780fc79044e5bccf438857dbb48732e3a30bc8c248e30d28037ade912808542022-06-21 7:28:24101 days 12 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614625,998 GLMR
0xf09c2394037ebdaae1a91c94af132594ee2428e0cc79d063266a10e1285542ea12785532022-06-20 23:09:24101 days 21 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614619,047 GLMR
0x8118a264c421dd3fe25c4a83d30de999da3719771f39f25b8df96ef01cd7381312775382022-06-20 19:31:48102 days 40 mins ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614610,000 GLMR
0xb5ba49ba7ea69ec813c08ff37518e313216c37b748a88248b30d313d83786f1612750352022-06-20 10:21:00102 days 9 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614611,960 GLMR
0x5641c0b0b8d81f127ce1b9fb145b67e33995d5e1358a061659152166a65ff37b12736542022-06-20 5:24:54102 days 14 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614622,624 GLMR
0x99fdd49319ed47271dbaef61346eb769e2b14df40febb374879d02af244b193912719962022-06-19 23:25:48102 days 20 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614612,000 GLMR
0x8d2eb22c32ee5d1d7e8b76dc2e21390918648606383c34221ba070f3ab81ef4212680192022-06-19 9:02:48103 days 11 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af3561462,500 GLMR
0xa7c01baa19e2e2f5370d4ac66d79ff50cda6e24965af7a6d934eb0bf256b6db112673312022-06-19 6:35:36103 days 13 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614614,000 GLMR
0xdce036036987cd1436e9a212c28f199e2fa278b21671c94f070ac0dd5e552ee412665152022-06-19 3:41:30103 days 16 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af356146155 GLMR
0x5f6770a9ad33898158e352a8cc98e49f8726d457106e7fafbee06d0c5087d50112661812022-06-19 2:29:48103 days 17 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614616,990 GLMR
0x1a21923f96f6e7067beb9c064160e71393a7f92f44c36be85b0613ac2e2ad29b12661672022-06-19 2:26:48103 days 17 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614612,202 GLMR
0xc8ff4552222b375a8a84eb891ae6da4341afa3b8a017fcde5e233fbee402388612659052022-06-19 1:31:36103 days 18 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af3561465,392.739184959204823852 GLMR
0xc665109f865dd0be9a5bd7de67ba97d0cf5dac569e1cafcd23a10ce2089e778d12640052022-06-18 18:42:48104 days 1 hr ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614612,800 GLMR
0x90cc56646102752bc866527590d8f958d28c12cd993992cbd3429b511276f94b12629022022-06-18 14:46:48104 days 5 hrs ago Ola Finance: Maximilion 0x356f621a437556c455932fb5507ab3f3af35614613,000 GLMR
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ONativeDelegator

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at moonbeam.moonscan.io on 2022-02-04
*/

pragma solidity ^0.5.16;

/**
  * @title Compound's InterestRateModel Interface
  * @author Compound
  */
contract InterestRateModel {
    /// @notice Indicator that this is an InterestRateModel contract (for inspection)
    bool public constant isInterestRateModel = true;

    /**
      * @notice Calculates the current borrow interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amount of reserves the market has
      * @return The borrow rate per block (as a percentage, and scaled by 1e18)
      */
    function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint);

    /**
      * @notice Calculates the current supply interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amount of reserves the market has
      * @param reserveFactorMantissa The current reserve factor the market has
      * @return The supply rate per block (as a percentage, and scaled by 1e18)
      */
    function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint);

}












contract ComptrollerErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        COMPTROLLER_MISMATCH,
        INSUFFICIENT_SHORTFALL,
        INSUFFICIENT_LIQUIDITY,
        INVALID_CLOSE_FACTOR,
        INVALID_COLLATERAL_FACTOR,
        INVALID_LIQUIDATION_INCENTIVE,
        MARKET_NOT_ENTERED, // no longer possible
        MARKET_NOT_LISTED,
        MARKET_ALREADY_LISTED,
        MATH_ERROR,
        NONZERO_BORROW_BALANCE,
        PRICE_ERROR,
        REJECTION,
        SNAPSHOT_ERROR,
        TOO_MANY_ASSETS,
        TOO_MUCH_REPAY,

        // OLA_ADDITIONS : All Enums from here
        NOT_IN_MARKET,
        TOO_LITTLE_BORROW,
        IN_FRESH_LIQUIDATION_LIMITED_PERIOD,
        INVALID_LIQUIDATION_FACTOR,
        BORROWED_AGAINST_FAILED,
        TOTAL_BORROWED_AGAINST_TOO_HIGH,
        TOO_MUCH_COLLATERAL_ACTIVATION,

        // V0.02
        NOT_APPROVED_TO_MINT,
        NOT_APPROVED_TO_BORROW
    }

    enum FailureInfo {
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
        EXIT_MARKET_BALANCE_OWED,
        EXIT_MARKET_REJECTION,
        SET_CLOSE_FACTOR_OWNER_CHECK,
        SET_CLOSE_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_OWNER_CHECK,
        SET_COLLATERAL_FACTOR_NO_EXISTS,
        SET_COLLATERAL_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_WITHOUT_PRICE,
        SET_IMPLEMENTATION_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_VALIDATION,
        SET_MAX_ASSETS_OWNER_CHECK,
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
        SET_PRICE_ORACLE_OWNER_CHECK,
        SUPPORT_MARKET_EXISTS,
        SUPPORT_MARKET_OWNER_CHECK,
        SET_PAUSE_GUARDIAN_OWNER_CHECK,

        // OLA_ADDITIONS : All Enums from here
        SET_LIQUIDATION_INCENTIVE_NO_EXISTS,
        SET_LIQUIDATION_INCENTIVE_WITHOUT_PRICE,
        SET_LIQUIDATION_FACTOR_OWNER_CHECK,
        SET_LIQUIDATION_FACTOR_NO_EXISTS,
        SET_LIQUIDATION_FACTOR_VALIDATION,
        SET_LIQUIDATION_FACTOR_WITHOUT_PRICE,
        SET_LIQUIDATION_FACTOR_LOWER_THAN_COLLATERAL_FACTOR,
        SET_LIQUIDATION_FACTOR_LOWER_THAN_EXISTING_FACTOR,
        SET_COLLATERAL_FACTOR_HIGHER_THAN_LIQUIDATION_FACTOR,
        SET_RAIN_MAKER_OWNER_CHECK,
        ENTER_MARKET_NOT_ALLOWED,
        UPDATE_LN_VERSION_ADMIN_OWNER_CHECK,
        // V0.002
        SET_BOUNCER_OWNER_CHECK,
        SET_LIMIT_MINTING_OWNER_CHECK,
        SET_LIMIT_BORROWING_OWNER_CHECK,
        SET_MIN_BORROW_AMOUNT_USD_OWNER_CHECK,
        SUPPORT_NEW_MARKET_OWNER_CHECK,
        SUPPORT_NEW_MARKET_COMBINATION_CHECK
    }

    /**
      * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
      * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
      **/
    event Failure(uint error, uint info, uint detail);

    /**
      * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
      */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
      * @dev use this when reporting an opaque error from an upgradeable collaborator contract
      */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

contract TokenErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        BAD_INPUT,
        COMPTROLLER_REJECTION,
        COMPTROLLER_CALCULATION_ERROR,
        INTEREST_RATE_MODEL_ERROR,
        INVALID_ACCOUNT_PAIR,
        INVALID_CLOSE_AMOUNT_REQUESTED,
        INVALID_COLLATERAL_FACTOR,
        MATH_ERROR,
        MARKET_NOT_FRESH,
        MARKET_NOT_LISTED,
        TOKEN_INSUFFICIENT_ALLOWANCE,
        TOKEN_INSUFFICIENT_BALANCE,
        TOKEN_INSUFFICIENT_CASH,
        TOKEN_TRANSFER_IN_FAILED,
        TOKEN_TRANSFER_OUT_FAILED,

        // OLA_ADDITIONS : All Enums from here
        BAD_SYSTEM_PARAMS
    }

    /*
     * Notice: FailureInfo (but not Error) is kept in alphabetical order
     *       This is because FailureInfo grows significantly faster, and
     *       the order of Error has some meaning, while the order of FailureInfo
     *       is entirely arbitrary.
     */
    enum FailureInfo {
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,
        ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,
        ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,
        BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        BORROW_ACCRUE_INTEREST_FAILED,
        BORROW_CASH_NOT_AVAILABLE,
        BORROW_FRESHNESS_CHECK,
        BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
        BORROW_MARKET_NOT_LISTED,
        BORROW_COMPTROLLER_REJECTION,
        LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,
        LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,
        LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,
        LIQUIDATE_COMPTROLLER_REJECTION,
        LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,
        LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,
        LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,
        LIQUIDATE_FRESHNESS_CHECK,
        LIQUIDATE_LIQUIDATOR_IS_BORROWER,
        LIQUIDATE_REPAY_BORROW_FRESH_FAILED,
        LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,
        LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,
        LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,
        LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,
        LIQUIDATE_SEIZE_TOO_MUCH,
        MINT_ACCRUE_INTEREST_FAILED,
        MINT_COMPTROLLER_REJECTION,
        MINT_EXCHANGE_CALCULATION_FAILED,
        MINT_EXCHANGE_RATE_READ_FAILED,
        MINT_FRESHNESS_CHECK,
        MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
        MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        MINT_TRANSFER_IN_FAILED,
        MINT_TRANSFER_IN_NOT_POSSIBLE,
        REDEEM_ACCRUE_INTEREST_FAILED,
        REDEEM_COMPTROLLER_REJECTION,
        REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,
        REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,
        REDEEM_EXCHANGE_RATE_READ_FAILED,
        REDEEM_FRESHNESS_CHECK,
        REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
        REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        REDEEM_TRANSFER_OUT_NOT_POSSIBLE,
        REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,
        REDUCE_RESERVES_ADMIN_CHECK,
        REDUCE_RESERVES_CASH_NOT_AVAILABLE,
        REDUCE_RESERVES_FRESH_CHECK,
        REDUCE_RESERVES_VALIDATION,
        REPAY_BEHALF_ACCRUE_INTEREST_FAILED,
        REPAY_BORROW_ACCRUE_INTEREST_FAILED,
        REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_COMPTROLLER_REJECTION,
        REPAY_BORROW_FRESHNESS_CHECK,
        REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,
        SET_COLLATERAL_FACTOR_OWNER_CHECK,
        SET_COLLATERAL_FACTOR_VALIDATION,
        SET_COMPTROLLER_OWNER_CHECK,
        SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,
        SET_INTEREST_RATE_MODEL_FRESH_CHECK,
        SET_INTEREST_RATE_MODEL_OWNER_CHECK,
        SET_MAX_ASSETS_OWNER_CHECK,
        SET_ORACLE_MARKET_NOT_LISTED,
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,
        SET_RESERVE_FACTOR_ADMIN_CHECK,
        SET_RESERVE_FACTOR_FRESH_CHECK,
        SET_RESERVE_FACTOR_BOUNDS_CHECK,
        TRANSFER_COMPTROLLER_REJECTION,
        TRANSFER_NOT_ALLOWED,
        TRANSFER_NOT_ENOUGH,
        TRANSFER_TOO_MUCH,
        ADD_RESERVES_ACCRUE_INTEREST_FAILED,
        ADD_RESERVES_FRESH_CHECK,
        ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE,

        // OLA_ADDITIONS : All Enums from here
        REDUCE_RESERVES_OLA_PART_CALCULATION_FAILED
    }

    /**
      * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
      * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
      **/
    event Failure(uint error, uint info, uint detail);

    /**
      * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
      */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
      * @dev use this when reporting an opaque error from an upgradeable collaborator contract
      */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}




/**
  * @title Careful Math
  * @author Compound
  * @notice Derived from OpenZeppelin's SafeMath library
  *         https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
  */
contract CarefulMath {

    /**
     * @dev Possible error codes that we can return
     */
    enum MathError {
        NO_ERROR,
        DIVISION_BY_ZERO,
        INTEGER_OVERFLOW,
        INTEGER_UNDERFLOW
    }

    /**
    * @dev Multiplies two numbers, returns an error on overflow.
    */
    function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (a == 0) {
            return (MathError.NO_ERROR, 0);
        }

        uint c = a * b;

        if (c / a != b) {
            return (MathError.INTEGER_OVERFLOW, 0);
        } else {
            return (MathError.NO_ERROR, c);
        }
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b == 0) {
            return (MathError.DIVISION_BY_ZERO, 0);
        }

        return (MathError.NO_ERROR, a / b);
    }

    /**
    * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
    */
    function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b <= a) {
            return (MathError.NO_ERROR, a - b);
        } else {
            return (MathError.INTEGER_UNDERFLOW, 0);
        }
    }

    /**
    * @dev Adds two numbers, returns an error on overflow.
    */
    function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
        uint c = a + b;

        if (c >= a) {
            return (MathError.NO_ERROR, c);
        } else {
            return (MathError.INTEGER_OVERFLOW, 0);
        }
    }

    /**
    * @dev add a and b and then subtract c
    */
    function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {
        (MathError err0, uint sum) = addUInt(a, b);

        if (err0 != MathError.NO_ERROR) {
            return (err0, 0);
        }

        return subUInt(sum, c);
    }
}


/**
 * @title Exponential module for storing fixed-precision decimals
 * @author Compound
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract ExponentialNoError {
    uint constant expScale = 1e18;
    uint constant doubleScale = 1e36;
    uint constant halfExpScale = expScale/2;
    uint constant mantissaOne = expScale;

    struct Exp {
        uint mantissa;
    }

    struct Double {
        uint mantissa;
    }

    /**
     * @dev Truncates the given exp to a whole number value.
     *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
     */
    function truncate(Exp memory exp) pure internal returns (uint) {
        // Note: We are not using careful Math here as we're performing a division that cannot fail
        return exp.mantissa / expScale;
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return truncate(product);
    }

    /**
     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
     */
    function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return add_(truncate(product), addend);
    }

    /**
     * @dev Checks if first Exp is less than second Exp.
     */
    function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa < right.mantissa;
    }

    /**
     * @dev Checks if left Exp <= right Exp.
     */
    function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa <= right.mantissa;
    }

    /**
     * @dev Checks if left Exp > right Exp.
     */
    function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa > right.mantissa;
    }

    /**
     * @dev returns true if Exp is exactly zero
     */
    function isZeroExp(Exp memory value) pure internal returns (bool) {
        return value.mantissa == 0;
    }

    function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {
        require(n < 2**224, errorMessage);
        return uint224(n);
    }

    function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(uint a, uint b) pure internal returns (uint) {
        return add_(a, b, "addition overflow");
    }

    function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        uint c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(uint a, uint b) pure internal returns (uint) {
        return sub_(a, b, "subtraction underflow");
    }

    function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
    }

    function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Exp memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / expScale;
    }

    function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
    }

    function mul_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Double memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / doubleScale;
    }

    function mul_(uint a, uint b) pure internal returns (uint) {
        return mul_(a, b, "multiplication overflow");
    }

    function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        if (a == 0 || b == 0) {
            return 0;
        }
        uint c = a * b;
        require(c / a == b, errorMessage);
        return c;
    }

    function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
    }

    function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Exp memory b) pure internal returns (uint) {
        return div_(mul_(a, expScale), b.mantissa);
    }

    function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
    }

    function div_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Double memory b) pure internal returns (uint) {
        return div_(mul_(a, doubleScale), b.mantissa);
    }

    function div_(uint a, uint b) pure internal returns (uint) {
        return div_(a, b, "divide by zero");
    }

    function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b > 0, errorMessage);
        return a / b;
    }

    function fraction(uint a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a, doubleScale), b)});
    }
}


/**
 * @title Exponential module for storing fixed-precision decimals
 * @author Compound
 * @dev Legacy contract for compatibility reasons with existing contracts that still use MathError
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract Exponential is CarefulMath, ExponentialNoError {
    /**
     * @dev Creates an exponential from numerator and denominator values.
     *      Note: Returns an error if (`num` * 10e18) > MAX_INT,
     *            or if `denom` is zero.
     */
    function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        (MathError err1, uint rational) = divUInt(scaledNumerator, denom);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: rational}));
    }

    /**
     * @dev Adds two exponentials, returning a new exponential.
     */
    function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        (MathError error, uint result) = addUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Subtracts two exponentials, returning a new exponential.
     */
    function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        (MathError error, uint result) = subUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Multiply an Exp by a scalar, returning a new Exp.
     */
    function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(product));
    }

    /**
     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
     */
    function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return addUInt(truncate(product), addend);
    }

    /**
     * @dev Divide an Exp by a scalar, returning a new Exp.
     */
    function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
    }

    /**
     * @dev Divide a scalar by an Exp, returning a new Exp.
     */
    function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {
        /*
          We are doing this as:
          getExp(mulUInt(expScale, scalar), divisor.mantissa)

          How it works:
          Exp = a / b;
          Scalar = s;
          `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
        */
        (MathError err0, uint numerator) = mulUInt(expScale, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }
        return getExp(numerator, divisor.mantissa);
    }

    /**
     * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
     */
    function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {
        (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(fraction));
    }

    /**
     * @dev Multiplies two exponentials, returning a new exponential.
     */
    function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {

        (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        // We add half the scale before dividing so that we get rounding instead of truncation.
        //  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
        // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
        (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);
        // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
        assert(err2 == MathError.NO_ERROR);

        return (MathError.NO_ERROR, Exp({mantissa: product}));
    }

    /**
     * @dev Multiplies two exponentials given their mantissas, returning a new exponential.
     */
    function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {
        return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
    }

    /**
     * @dev Multiplies three exponentials, returning a new exponential.
     */
    function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {
        (MathError err, Exp memory ab) = mulExp(a, b);
        if (err != MathError.NO_ERROR) {
            return (err, ab);
        }
        return mulExp(ab, c);
    }

    /**
     * @dev Divides two exponentials, returning a new exponential.
     *     (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
     *  which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
     */
    function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        return getExp(a.mantissa, b.mantissa);
    }
}



/**
 * @title ERC 20 Token Standard Interface
 *  https://eips.ethereum.org/EIPS/eip-20
 */
interface EIP20Interface {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    /**
      * @notice Get the total number of tokens in circulation
      * @return The supply of tokens
      */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return Whether or not the transfer succeeded
      */
    function transfer(address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return Whether or not the transfer succeeded
      */
    function transferFrom(address src, address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved (-1 means infinite)
      * @return Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return The number of tokens allowed to be spent (-1 means infinite)
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}



interface RegistryForOToken {
    function isSupportedInterestRateModel(address interestRateModel) external returns (bool);
    function olaBankAddress() external view returns (address payable);
    function blocksBased() external view returns (bool);
}

interface ComptrollerForOToken {
    function adminBankAddress() external view returns (address payable);
}


contract ComptrollerInterface {
    /// @notice Indicator that this is a Comptroller contract (for inspection)
    bool public constant isComptroller = true;

    /*** OLA_ADDITIONS : registry getter ***/
    /*** Registry ***/
    function getRegistry() external view returns (address);

    /*** Assets supported by the Comptroller ***/
    function getAllMarkets() public view returns (CToken[] memory);

    /*** OLA_ADDITIONS : peripheral checkers ***/
    /*** Peripherals ***/
    function hasRainMaker() view public returns (bool);
    function hasBouncer() view public returns (bool);

    /*** Assets You Are In ***/

    function enterMarkets(address[] calldata cTokens) external returns (uint[] memory);
    function exitMarket(address cToken) external returns (uint);

    /*** Policy Hooks ***/

    function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint);
    function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external;

    function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint);
    function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external;

    function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint);
    function borrowVerify(address cToken, address borrower, uint borrowAmount) external;

    function repayBorrowAllowed(
        address cToken,
        address payer,
        address borrower,
        uint repayAmount) external returns (uint);
    function repayBorrowVerify(
        address cToken,
        address payer,
        address borrower,
        uint repayAmount,
        uint borrowerIndex) external;

    function liquidateBorrowAllowed(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount) external returns (uint);
    function liquidateBorrowVerify(
        address cTokenBorrowed,
        address cTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount,
        uint seizeTokens) external;

    function seizeAllowed(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) external returns (uint);
    function seizeVerify(
        address cTokenCollateral,
        address cTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) external;

    function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint);
    function transferVerify(address cToken, address src, address dst, uint transferTokens) external;

    /*** Liquidity/Liquidation Calculations ***/

    function liquidateCalculateSeizeTokens(
        address cTokenBorrowed,
        address cTokenCollateral,
        uint repayAmount) external view returns (uint, uint);
}




/**
 * @title EIP20NonStandardInterface
 * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
 *  See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
 */
interface EIP20NonStandardInterface {

    /**
     * @notice Get the total number of tokens in circulation
     * @return The supply of tokens
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transfer(address dst, uint256 amount) external;

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transferFrom(address src, address dst, uint256 amount) external;

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved
      * @return Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return The number of tokens allowed to be spent
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}


/**
 * OLA_ADDITIONS : This base admin storage.
 */
contract CTokenAdminStorage {
    /**
     * @notice Administrator for this contract
     */
    address payable public admin;

    /**
     * @notice Pending administrator for this contract
     */
    address payable public pendingAdmin;

    /**
     * @notice Contract which oversees inter-cToken operations
     */
    ComptrollerInterface public comptroller;

    /**
     * @notice Implementation address for this contract
     */
    address public implementation;

    // OLA_ADDITIONS : Contract hash name
    bytes32 public contractNameHash;
}

/**
 * @notice DO NOT ADD ANY MORE STORAGE VARIABLES HERE (add them to their respective type storage)
 */
contract CTokenStorage is CTokenAdminStorage {
    /**
     * @dev Guard variable for re-entrancy checks
     */
    bool internal _notEntered;

    /**
     * @notice EIP-20 token name for this token
     */
    string public name;

    /**
     * @notice EIP-20 token symbol for this token
     */
    string public symbol;

    /**
     * @notice EIP-20 token decimals for this token
     */
    uint8 public decimals;

    /**
     * @notice Underlying asset for this CToken
     */
    address public underlying;

    // @notice Indicates if the calculations should be blocks or time based
    bool public blocksBased;

    /**
     * @notice Model which tells what the current interest rate should be
     */
    InterestRateModel public interestRateModel;

    /**
     * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)
     */
    uint internal initialExchangeRateMantissa;

    /**
     * @notice Fraction of interest currently set aside for reserves
     */
    uint public reserveFactorMantissa;

    /**
     * @notice Block number that interest was last accrued at
     */
    uint public accrualBlockNumber;

    /**
     * @notice Block number that interest was last accrued at
     */
    uint public accrualBlockTimestamp;

    /**
     * @notice Accumulator of the total earned interest rate since the opening of the market
     */
    uint public borrowIndex;

    /**
     * @notice Total amount of outstanding borrows of the underlying in this market
     */
    uint public totalBorrows;

    /**
     * OLA_ADDITIONS : Removed option to 'add reserves' as it makes no sense when reducing reserves
     *                 sends a part to Ola Bank.
     * @notice Total amount of reserves of the underlying held in this market
     */
    uint public totalReserves;

    /**
     * @notice Total number of tokens in circulation
     */
    uint public totalSupply;

    /**
     * @notice Official record of token balances for each account
     */
    mapping (address => uint) internal accountTokens;

    /**
     * @notice Approved token transfer amounts on behalf of others
     */
    mapping (address => mapping (address => uint)) internal transferAllowances;

    /**
     * @notice Container for borrow balance information
     * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
     * @member interestIndex Global borrowIndex as of the most recent balance-changing action
     */
    struct BorrowSnapshot {
        uint principal;
        uint interestIndex;
    }

    /**
     * @notice Mapping of account addresses to outstanding borrow balances
     */
    mapping(address => BorrowSnapshot) internal accountBorrows;

    // IMPORTANT : DO NOT ADD ANY MORE STORAGE VARIABLES HERE (add them to their respective type storage)
}

contract CTokenDelegatorInterface {

    /*** Implementation Events ***/

    /**
     * @notice Emitted when implementation is changed
     */
    event NewImplementation(address indexed oldImplementation, address indexed newImplementation);

    /**
     * @notice Emitted when implementation is not changed under a system version update
     */
    event ImplementationDidNotChange(address indexed implementation);


    /*** Implementation functions ***/

    // OLA_ADDITIONS : Update implementation from the Registry
    function updateImplementationFromRegistry(bool allowResign, bytes calldata becomeImplementationData) external returns (bool);
}

contract CTokenInterface {
    // OLA_ADDITIONS : "Underlying field"
    address constant public nativeCoinUnderlying = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);

    /**
     * OLA_ADDITIONS : This field
     * @notice This value is hard coded to 0.5 (50% for the Ola ecosystem and the LeN owner each)
     */
    uint constant public olaReserveFactorMantissa = 0.5e18;

    /**
     * @notice Indicator that this is a CToken contract (for inspection)
     */
    bool public constant isCToken = true;

    /**
     * @notice Maximum borrow rate that can ever be applied (.0005% / block)
     */
    uint internal constant borrowRateMaxMantissa = 0.0005e16;

    /**
     * @notice Maximum fraction of interest that can be set aside for reserves
     */
    uint internal constant reserveFactorMaxMantissa = 0.3e18;

    /**
     * OLA_ADDITIONS : This value
     * @notice Minimum fraction of interest that can be set aside for reserves
     */
    uint internal constant reserveFactorMinMantissa = 0.05e18;

    /*** Market Events ***/

    /**
     * @notice Event emitted when interest is accrued
     */
    event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);

    /**
     * @notice Event emitted when tokens are minted
     */
    event Mint(address minter, uint mintAmount, uint mintTokens);

    /**
     * @notice Event emitted when tokens are redeemed
     */
    event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);

    /**
     * @notice Event emitted when underlying is borrowed
     */
    event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);

    /**
     * @notice Event emitted when a borrow is repaid
     */
    event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);

    /**
     * @notice Event emitted when a borrow is liquidated
     */
    event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens);


    /*** Admin Events ***/

    /**
     * @notice Event emitted when pendingAdmin is changed
     */
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /**
     * @notice Event emitted when pendingAdmin is accepted, which means admin is updated
     */
    event NewAdmin(address oldAdmin, address newAdmin);

    /**
     * @notice Event emitted when Comptroller is changed
     */
    event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);

    /**
     * @notice Event emitted when interestRateModel is changed
     */
    event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);

    /**
     * @notice Event emitted when the reserve factor is changed
     */
    event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);

    // TODO : Change to 'adminBank'
    /**
     * @notice Event emitted when the reserves are reduced
     */
    event ReservesReduced(address admin, uint adminPart, address olaBank, uint olaPart, uint newTotalReserves);

    /**
     * @notice EIP20 Transfer event
     */
    event Transfer(address indexed from, address indexed to, uint amount);

    /**
     * @notice EIP20 Approval event
     */
    event Approval(address indexed owner, address indexed spender, uint amount);

    /**
     * @notice Failure event
     */
    event Failure(uint error, uint info, uint detail);

    /*** User Interface ***/

    function transfer(address dst, uint amount) external returns (bool);
    function transferFrom(address src, address dst, uint amount) external returns (bool);
    function approve(address spender, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function balanceOfUnderlying(address owner) external returns (uint);
    function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint);
    function borrowBalanceStored(address account) public view returns (uint);
    function exchangeRateStored() public view returns (uint);
    function getAccrualBlockNumber() external view returns (uint);
    function accrueInterest() public returns (uint);
    function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint);

    /*** Admin Functions ***/

    function _setPendingAdmin(address payable newPendingAdmin) external returns (uint);
    function _acceptAdmin() external returns (uint);
    function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint);
    function _reduceReserves(uint reduceAmount) external returns (uint);
    function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint);
}

/**
 * View functions that are not used by the core contracts.
 */
contract CTokenViewInterface {
    /*** View Interface ***/
    function borrowRatePerBlock() external view returns (uint);
    function supplyRatePerBlock() external view returns (uint);
    function totalBorrowsCurrent() external returns (uint);

    /**
     * @notice Used by the Maximilion
     */
    function borrowBalanceCurrent(address account) external returns (uint);
    function exchangeRateCurrent() public returns (uint);
    function getCash() external view returns (uint);
}

contract CErc20Interface {
    /*** User Interface ***/

    function mint(uint mintAmount) external returns (uint);
    function redeem(uint redeemTokens) external returns (uint);
    function redeemUnderlying(uint redeemAmount) external returns (uint);
    function borrow(uint borrowAmount) external returns (uint);
    function repayBorrow(uint repayAmount) external returns (uint);
    function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint);
    function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) external returns (uint);
    function sweepToken(EIP20NonStandardInterface token) external;
}

contract CErc20StorageV0_01 {}

contract CErc20StorageV0_02 is CErc20StorageV0_01 {}

contract ONativeInterface {
    /*** User Interface ***/

    function mint() external payable;
    function redeem(uint redeemTokens) external returns (uint);
    function redeemUnderlying(uint redeemAmount) external returns (uint);
    function borrow(uint borrowAmount) external returns (uint);
    function repayBorrow() external payable;
    function repayBorrowBehalf(address borrower) external payable;
    function liquidateBorrow(address borrower, CTokenInterface cTokenCollateral) external payable;
    function sweepToken(EIP20NonStandardInterface token) external;
}

contract CEtherStorageV0_01 {}

contract CEtherStorageV0_02 is CEtherStorageV0_01 {}

contract CDelegateInterface {
    /**
     * @notice Called by the delegator on a delegate to initialize it for duty
     * @dev Should revert if any issues arise which make it unfit for delegation
     * @param data The encoded bytes data for any initialization
     */
    function _becomeImplementation(bytes memory data) public;

    /**
     * @notice Called by the delegator on a delegate to forfeit its responsibility
     */
    function _resignImplementation() public;
}

contract OTokenCompoundingDepositStorage {

}

contract OTokenCompoundingDepositStorageV0_05 is OTokenCompoundingDepositStorage {

}

contract CLPStakingStorageV0_05 {

    /**
     * @notice The token that is distributed via the farm
     */
    address public rewardToken;

    /**
     * @notice The farm contract
     */
    address public farmAddress;

    /**
     * @notice The pool id in the farm
     */
    uint public pid;

    /**
     * @notice The market's last updated staking index
     */
    uint public marketStakingIndex;

    /// @notice The Reward Token index for each supplier as of the last time they accrued rewards
    mapping(address => uint) public supplierStakingIndex;

    /// @notice The Reward Token accrued but not yet transferred to each supplier
    mapping(address => uint) public rewardsAccrued;
}

contract CLPStakingInterfaceV0_05 {
    /**
     * @notice Event emitted when rewards-interest is accrued
     */
    event AccrueRewardsInterest(uint oldStakingIndex, uint newStakingIndex, uint oldReserves, uint newReserves);

    event DistributeSupplierRewards(address supplier, uint supplierDelta, uint marketStakignIndex);
}





interface RegistryForODelegator {
    function getImplementationForLn(address lnUnitroller, bytes32 contractNameHash) external returns (address);
}

/**
 * @title Ola's ODelegator Contract
 * @notice OTokens which delegate to an implementation
 * @author Ola
 */
contract ODelegator is CTokenAdminStorage, CTokenDelegatorInterface {

    /**
     * @notice Called by the Comptroller (most of the time) or by the admin (only via the constructor) to update the
     *         implementation of the delegator
     * @param implementation_ The address of the new implementation for delegation
     * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
     * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
     */
    function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) internal {
        if (allowResign) {
            delegateToImplementation(abi.encodeWithSignature("_resignImplementation()"));
        }

        // Basic sanity
        require(CToken(implementation_).isCToken(), "Not CTokens");

        address oldImplementation = implementation;
        implementation = implementation_;


        delegateToImplementation(abi.encodeWithSignature("_becomeImplementation(bytes)", becomeImplementationData));

        emit NewImplementation(oldImplementation, implementation);
    }

    /**
     * @notice Internal method to delegate execution to another contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     * @param callee The contract to delegatecall
     * @param data The raw data to delegatecall
     * @return The returned bytes from the delegatecall
     */
    function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returnData) = callee.delegatecall(data);
        assembly {
            if eq(success, 0) {
                revert(add(returnData, 0x20), returndatasize)
            }
        }
        return returnData;
    }

    /**
     * @notice Delegates execution to the implementation contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     * @param data The raw data to delegatecall
     * @return The returned bytes from the delegatecall
     */
    function delegateToImplementation(bytes memory data) public returns (bytes memory) {
        return delegateTo(implementation, data);
    }

    /**
     * @notice Delegates execution to an implementation contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     *  There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
     * @param data The raw data to delegatecall
     * @return The returned bytes from the delegatecall
     */
    function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
        (bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
        assembly {
            if eq(success, 0) {
                revert(add(returnData, 0x20), returndatasize)
            }
        }
        return abi.decode(returnData, (bytes));
    }

    function updateImplementationFromRegistry(bool allowResign, bytes calldata becomeImplementationData) external returns (bool) {
        require(msg.sender == address(comptroller), "Not comptroller");
        address implementationToSet = RegistryForODelegator(comptroller.getRegistry()).getImplementationForLn(address(comptroller), contractNameHash);
        require(implementationToSet != address(0), "No implementation");

        if (implementationToSet != implementation) {
            // New implementations always get set via the setter (post-initialize)
            _setImplementation(implementationToSet, allowResign, becomeImplementationData);
        } else {
            emit ImplementationDidNotChange(implementation);
        }

        return true;
    }

    /**
     * @notice Delegates execution to an implementation contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     */
    function () external payable {
        require(msg.value == 0,"ODelegator:fallback: cannot send value to fallback");

        // delegate all other functions to current implementation
        (bool success, ) = implementation.delegatecall(msg.data);

        assembly {
            let free_mem_ptr := mload(0x40)
            returndatacopy(free_mem_ptr, 0, returndatasize)

            switch success
            case 0 { revert(free_mem_ptr, returndatasize) }
            default { return(free_mem_ptr, returndatasize) }
        }
    }
}


/**
 * @title Ola's ONativeDelegator Contract
 * @notice OTokens which wrap a native coin underlying and delegate to an implementation
 * @author Ola
 */
contract ONativeDelegator is ODelegator, CTokenInterface, ONativeInterface {
    // OLA_ADDITIONS : This contract name hash
    bytes32 constant public ONativeDelegatorContractHash = keccak256("ONativeDelegator");

    /**
     * @notice Construct a new money market
     * @param comptroller_ The address of the Comptroller
     * @param interestRateModel_ The address of the interest rate model
     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
     * @param name_ ERC-20 name of this token
     * @param symbol_ ERC-20 symbol of this token
     * @param decimals_ ERC-20 decimal precision of this token
     * @param admin_ Address of the administrator of this token
     * @param becomeImplementationData The encoded args for becomeImplementation
     */
    constructor(ComptrollerInterface comptroller_,
                InterestRateModel interestRateModel_,
                uint initialExchangeRateMantissa_,
                string memory name_,
                string memory symbol_,
                uint8 decimals_,
                address payable admin_,
                bytes memory becomeImplementationData) public {
        // Creator of the contract is admin during initialization
        admin = msg.sender;

        // Initialize name hash
        contractNameHash = ONativeDelegatorContractHash;

        address oNativeImplementation = RegistryForODelegator(comptroller_.getRegistry()).getImplementationForLn(address(comptroller_), ONativeDelegatorContractHash);

        // First delegate gets to initialize the delegator (i.e. storage contract)
        delegateTo(oNativeImplementation, abi.encodeWithSignature("initialize(address,address,uint256,string,string,uint8)",
                                                            comptroller_,
                                                            interestRateModel_,
                                                            initialExchangeRateMantissa_,
                                                            name_,
                                                            symbol_,
                                                            decimals_));

        // New implementations always get set via the setter (post-initialize)
        _setImplementation(oNativeImplementation, false, becomeImplementationData);

        // Set the proper admin now that initialization is done
        admin = admin_;
    }

    /**
 * @notice Sender supplies assets into the market and receives OTokens in exchange
 * @dev Reverts upon any failure
 */
    function mint() external payable {
        delegateToImplementation(abi.encodeWithSignature("mint()"));
    }

    /**
     * @notice Sender redeems cTokens in exchange for the underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemTokens The number of cTokens to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeem(uint redeemTokens) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("redeem(uint256)", redeemTokens));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The amount of underlying to redeem
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemUnderlying(uint redeemAmount) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("redeemUnderlying(uint256)", redeemAmount));
        return abi.decode(data, (uint));
    }

    /**
      * @notice Sender borrows assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrow(uint borrowAmount) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("borrow(uint256)", borrowAmount));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Sender repays their own borrow
     * @dev Reverts upon any failure
     */
    function repayBorrow() external payable {
        delegateToImplementation(abi.encodeWithSignature("repayBorrow()"));
    }

    /**
     * @notice Sender repays a borrow belonging to borrower
     * @dev Reverts upon any failure
     * @param borrower the account with the debt being payed off
     */
    function repayBorrowBehalf(address borrower) external payable {
        delegateToImplementation(abi.encodeWithSignature("repayBorrowBehalf(address)", borrower));
    }

    /**
     * @notice The sender liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @dev Reverts upon any failure
     * @param borrower The borrower of this cToken to be liquidated
     * @param cTokenCollateral The market in which to seize collateral from the borrower
     */
    function liquidateBorrow(address borrower, CTokenInterface cTokenCollateral) external payable {
        delegateToImplementation(abi.encodeWithSignature("liquidateBorrow(address,address)", borrower, cTokenCollateral));
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint amount) external returns (bool) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("transfer(address,uint256)", dst, amount));
        return abi.decode(data, (bool));
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint256 amount) external returns (bool) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("transferFrom(address,address,uint256)", src, dst, amount));
        return abi.decode(data, (bool));
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint256 amount) external returns (bool) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("approve(address,uint256)", spender, amount));
        return abi.decode(data, (bool));
    }

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param owner The address of the account which owns the tokens to be spent
     * @param spender The address of the account which may transfer tokens
     * @return The number of tokens allowed to be spent (-1 means infinite)
     */
    function allowance(address owner, address spender) external view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("allowance(address,address)", owner, spender));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Get the token balance of the `owner`
     * @param owner The address of the account to query
     * @return The number of tokens owned by `owner`
     */
    function balanceOf(address owner) external view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("balanceOf(address)", owner));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Get the underlying balance of the `owner`
     * @dev This also accrues interest in a transaction
     * @param owner The address of the account to query
     * @return The amount of underlying owned by `owner`
     */
    function balanceOfUnderlying(address owner) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("balanceOfUnderlying(address)", owner));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Get a snapshot of the account's balances, and the cached exchange rate
     * @dev This is used by Comptroller to more efficiently perform liquidity checks.
     * @param account Address of the account to snapshot
     * @return (possible error, token balance, borrow balance, exchange rate mantissa)
     */
    function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getAccountSnapshot(address)", account));
        return abi.decode(data, (uint, uint, uint, uint));
    }

    /**
     * @notice Returns the current per-block borrow interest rate for this cToken
     * @return The borrow interest rate per block, scaled by 1e18
     */
    function borrowRatePerBlock() external view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("borrowRatePerBlock()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Returns the current per-block supply interest rate for this cToken
     * @return The supply interest rate per block, scaled by 1e18
     */
    function supplyRatePerBlock() external view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("supplyRatePerBlock()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Returns the current total borrows plus accrued interest
     * @return The total borrows with interest
     */
    function totalBorrowsCurrent() external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("totalBorrowsCurrent()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
     * @param account The address whose balance should be calculated after updating borrowIndex
     * @return The calculated balance
     */
    function borrowBalanceCurrent(address account) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("borrowBalanceCurrent(address)", account));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return The calculated balance
     */
    function borrowBalanceStored(address account) public view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("borrowBalanceStored(address)", account));
        return abi.decode(data, (uint));
    }

   /**
     * @notice Accrue interest then return the up-to-date exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateCurrent() public returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("exchangeRateCurrent()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the CToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateStored() public view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("exchangeRateStored()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Get cash balance of this cToken in the underlying asset
     * @return The quantity of underlying asset owned by this contract
     */
    function getCash() external view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getCash()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Get the accrual block number of this cToken
     * @return The accrual block number
     */
    function getAccrualBlockNumber() external view returns (uint) {
        bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getAccrualBlockNumber()"));
        return abi.decode(data, (uint));
    }

    /**
      * @notice Applies accrued interest to total borrows and reserves.
      * @dev This calculates interest accrued from the last checkpointed block
      *      up to the current block and writes new checkpoint to storage.
      */
    function accrueInterest() public returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("accrueInterest()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Transfers collateral tokens (this market) to the liquidator.
     * @dev Will fail unless called by another cToken during the process of liquidation.
     *  Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.
     * @param liquidator The account receiving seized collateral
     * @param borrower The account having collateral seized
     * @param seizeTokens The number of cTokens to seize
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("seize(address,address,uint256)", liquidator, borrower, seizeTokens));
        return abi.decode(data, (uint));
    }

    /**
     * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (Timelock)
     * @param token The address of the ERC-20 token to sweep
     */
    function sweepToken(EIP20NonStandardInterface token) external {
        delegateToImplementation(abi.encodeWithSignature("sweepToken(address)", token));
    }


    /*** Admin Functions ***/

    /**
      * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @param newPendingAdmin New pending admin.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setPendingAdmin(address)", newPendingAdmin));
        return abi.decode(data, (uint));
    }

    /**
      * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
      * @dev Admin function to accrue interest and set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setReserveFactor(uint256)", newReserveFactorMantissa));
        return abi.decode(data, (uint));
    }

    /**
      * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
      * @dev Admin function for pending admin to accept role and update admin
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _acceptAdmin() external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("_acceptAdmin()"));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Accrues interest and reduces reserves by transferring to admin
     * @param reduceAmount Amount of reduction to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _reduceReserves(uint reduceAmount) external returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("_reduceReserves(uint256)", reduceAmount));
        return abi.decode(data, (uint));
    }

    /**
     * @notice Accrues interest and updates the interest rate model using _setInterestRateModelFresh
     * @dev Admin function to accrue interest and update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {
        bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setInterestRateModel(address)", newInterestRateModel));
        return abi.decode(data, (uint));
    }
}

/**
 * @title Compound's CToken Contract
 * @notice Abstract base for CTokens
 * @author Compound
 */
contract CToken is CTokenStorage, CTokenInterface, CTokenViewInterface, Exponential, TokenErrorReporter {
    /**
     * @notice Initialize the money market
     * @param comptroller_ The address of the Comptroller
     * @param interestRateModel_ The address of the interest rate model
     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
     * @param name_ EIP-20 name of this token
     * @param symbol_ EIP-20 symbol of this token
     * @param decimals_ EIP-20 decimal precision of this token
     */
    function initialize(ComptrollerInterface comptroller_,
        InterestRateModel interestRateModel_,
        uint initialExchangeRateMantissa_,
        string memory name_,
        string memory symbol_,
        uint8 decimals_) public {
        require(msg.sender == admin, "only admin may initialize the market");
        require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");

        // Set initial exchange rate
        initialExchangeRateMantissa = initialExchangeRateMantissa_;
        require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero.");

        // Set the Comptroller
        uint err = _setComptroller(comptroller_);
        require(err == uint(Error.NO_ERROR), "setting comptroller failed");

        // Initialize block number and borrow index (block number mocks depend on Comptroller being set)
        accrualBlockNumber = getBlockNumber();
        accrualBlockTimestamp = getBlockTimestamp();
        borrowIndex = mantissaOne;

        // Set the calculation based flag from the ministry
        RegistryForOToken ministry = RegistryForOToken(comptroller.getRegistry());
        blocksBased = ministry.blocksBased();

        // Set the interest rate model (depends on block number / borrow index)
        err = _setInterestRateModelFresh(interestRateModel_);
        require(err == uint(Error.NO_ERROR), "setting interest rate model failed");

        name = name_;
        symbol = symbol_;
        decimals = decimals_;

        // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)
        _notEntered = true;
    }

    /**
     * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`
     * @dev Called by both `transfer` and `transferFrom` internally
     * @param spender The address of the account performing the transfer
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param tokens The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {
        /* Fail if transfer not allowed */
        uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens);
        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.TRANSFER_COMPTROLLER_REJECTION, allowed);
        }

        /* Do not allow self-transfers */
        if (src == dst) {
            return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);
        }

        /* Get the allowance, infinite for the account owner */
        uint startingAllowance = 0;
        if (spender == src) {
            startingAllowance = uint(-1);
        } else {
            startingAllowance = transferAllowances[src][spender];
        }

        /* Do the calculations, checking for {under,over}flow */
        MathError mathErr;
        uint allowanceNew;
        uint srcTokensNew;
        uint dstTokensNew;

        (mathErr, allowanceNew) = subUInt(startingAllowance, tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED);
        }

        (mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH);
        }

        (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        accountTokens[src] = srcTokensNew;
        accountTokens[dst] = dstTokensNew;

        /* Eat some of the allowance (if necessary) */
        if (startingAllowance != uint(-1)) {
            transferAllowances[src][spender] = allowanceNew;
        }

        /* We emit a Transfer event */
        emit Transfer(src, dst, tokens);

        // unused function
        comptroller.transferVerify(address(this), src, dst, tokens);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint256 amount) external nonReentrant returns (bool) {
        return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR);
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) {
        return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR);
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint256 amount) external returns (bool) {
        address src = msg.sender;
        transferAllowances[src][spender] = amount;
        emit Approval(src, spender, amount);
        return true;
    }

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param owner The address of the account which owns the tokens to be spent
     * @param spender The address of the account which may transfer tokens
     * @return The number of tokens allowed to be spent (-1 means infinite)
     */
    function allowance(address owner, address spender) external view returns (uint256) {
        return transferAllowances[owner][spender];
    }

    /**
     * @notice Get the token balance of the `owner`
     * @param owner The address of the account to query
     * @return The number of tokens owned by `owner`
     */
    function balanceOf(address owner) external view returns (uint256) {
        return accountTokens[owner];
    }

    /**
     * @notice Get the underlying balance of the `owner`
     * @dev This also accrues interest in a transaction
     * @param owner The address of the account to query
     * @return The amount of underlying owned by `owner`
     */
    function balanceOfUnderlying(address owner) external returns (uint) {
        Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
        (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);
        require(mErr == MathError.NO_ERROR, "balance could not be calculated");
        return balance;
    }

    /**
     * @notice Get a snapshot of the account's balances, and the cached exchange rate
     * @dev This is used by Comptroller to more efficiently perform liquidity checks.
     * @param account Address of the account to snapshot
     * @return (possible error, token balance, borrow balance, exchange rate mantissa)
     */
    function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {
        uint cTokenBalance = accountTokens[account];
        uint borrowBalance;
        uint exchangeRateMantissa;

        MathError mErr;

        (mErr, borrowBalance) = borrowBalanceStoredInternal(account);
        if (mErr != MathError.NO_ERROR) {
            return (uint(Error.MATH_ERROR), 0, 0, 0);
        }

        (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();
        if (mErr != MathError.NO_ERROR) {
            return (uint(Error.MATH_ERROR), 0, 0, 0);
        }

        return (uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa);
    }

    /**
     * @dev Function to simply retrieve block number
     *  This exists mainly for inheriting test contracts to stub this result.
     */
    function getBlockNumber() internal view returns (uint) {
        return block.number;
    }

    /**
     * @dev Function to simply retrieve block timestamp
     *  This exists mainly for inheriting test contracts to stub this result.
     */
    function getBlockTimestamp() internal view returns (uint) {
        return block.timestamp;
    }

    /**
     * @notice Returns the current per-block borrow interest rate for this cToken
     * @return The borrow interest rate per block, scaled by 1e18
     */
    function borrowRatePerBlock() external view returns (uint) {
        return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);
    }

    /**
     * @notice Returns the current per-block supply interest rate for this cToken
     * @return The supply interest rate per block, scaled by 1e18
     */
    function supplyRatePerBlock() external view returns (uint) {
        return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);
    }

    /**
     * @notice Returns the current total borrows plus accrued interest
     * @return The total borrows with interest
     */
    function totalBorrowsCurrent() external nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return totalBorrows;
    }

    /**
     * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
     * @param account The address whose balance should be calculated after updating borrowIndex
     * @return The calculated balance
     */
    function borrowBalanceCurrent(address account) external nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return borrowBalanceStored(account);
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return The calculated balance
     */
    function borrowBalanceStored(address account) public view returns (uint) {
        (MathError err, uint result) = borrowBalanceStoredInternal(account);
        require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed");
        return result;
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return (error code, the calculated balance or 0 if error code is non-zero)
     */
    function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) {
        /* Note: we do not assert that the market is up to date */
        MathError mathErr;
        uint principalTimesIndex;
        uint result;

        /* Get borrowBalance and borrowIndex */
        BorrowSnapshot storage borrowSnapshot = accountBorrows[account];

        /* If borrowBalance = 0 then borrowIndex is likely also 0.
         * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
         */
        if (borrowSnapshot.principal == 0) {
            return (MathError.NO_ERROR, 0);
        }

        /* Calculate new borrow balance using the interest index:
         *  recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
         */
        (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        return (MathError.NO_ERROR, result);
    }

    /**
     * @notice Accrue interest then return the up-to-date exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateCurrent() public nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return exchangeRateStored();
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the CToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateStored() public view returns (uint) {
        (MathError err, uint result) = exchangeRateStoredInternal();
        require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed");
        return result;
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the CToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return (error code, calculated exchange rate scaled by 1e18)
     */
    function exchangeRateStoredInternal() internal view returns (MathError, uint) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            /*
             * If there are no tokens minted:
             *  exchangeRate = initialExchangeRate
             */
            return (MathError.NO_ERROR, initialExchangeRateMantissa);
        } else {
            /*
             * Otherwise:
             *  exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
             */
            uint totalCash = getCashPrior();
            uint cashPlusBorrowsMinusReserves;
            Exp memory exchangeRate;
            MathError mathErr;

            (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);
            if (mathErr != MathError.NO_ERROR) {
                return (mathErr, 0);
            }

            (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);
            if (mathErr != MathError.NO_ERROR) {
                return (mathErr, 0);
            }

            return (MathError.NO_ERROR, exchangeRate.mantissa);
        }
    }

    /**
     * @notice Get cash balance of this cToken in the underlying asset
     * @return The quantity of underlying asset owned by this contract
     */
    function getCash() external view returns (uint) {
        return getCashPrior();
    }

    /**
     * @notice Get the accrual block number of this cToken
     * @return The accrual block number
     */
    function getAccrualBlockNumber() external view returns (uint) {
        return accrualBlockNumber;
    }

    /**
     * @notice Applies accrued interest to total borrows and reserves
     * @dev This calculates interest accrued from the last checkpointed block
     *   up to the current block and writes new checkpoint to storage.
     */
    function accrueInterest() public returns (uint) {
        /* Remember the initial block number */
        uint currentBlockNumber = getBlockNumber();
        uint accrualBlockNumberPrior = accrualBlockNumber;
        uint currentBlockTimestamp = getBlockTimestamp();

        /* Short-circuit accumulating 0 interest */
        if (accrualBlockNumberPrior == currentBlockNumber) {
            return uint(Error.NO_ERROR);
        }

        // OLA_ADDITIONS : Distinction between time and block based calculations
        /* Calculate the number of blocks elapsed since the last accrual */
        MathError mathErr;
        uint delta;

        if (blocksBased) {
            (mathErr, delta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);
        } else {
            // This variable is defined here due to solidity limits
            uint accrualBlockTimestampPrior = accrualBlockTimestamp;

            /* Short-circuit accumulating 0 interest on time based chains + extra safety for weird timestamps */
            if (currentBlockTimestamp <= accrualBlockTimestampPrior) {
                return uint(Error.NO_ERROR);
            }

            (mathErr, delta) = subUInt(currentBlockTimestamp, accrualBlockTimestampPrior);
        }
        require(mathErr == MathError.NO_ERROR, "could not calculate delta");

        /* Read the previous values out of storage */
        uint cashPrior = getCashPrior();
        uint borrowsPrior = totalBorrows;
        uint reservesPrior = totalReserves;
        uint borrowIndexPrior = borrowIndex;

        /* Calculate the current borrow interest rate */
        uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);
        require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");

        /*
         * Calculate the interest accumulated into borrows and reserves and the new index:
         *  simpleInterestFactor = borrowRate * delta
         *  interestAccumulated = simpleInterestFactor * totalBorrows
         *  totalBorrowsNew = interestAccumulated + totalBorrows
         *  totalReservesNew = interestAccumulated * reserveFactor + totalReserves
         *  borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
         */

        Exp memory simpleInterestFactor;
        uint interestAccumulated;
        uint totalBorrowsNew;
        uint totalReservesNew;
        uint borrowIndexNew;

        (mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), delta);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We write the previously calculated values into storage */
        accrualBlockNumber = currentBlockNumber;
        accrualBlockTimestamp = currentBlockTimestamp;
        borrowIndex = borrowIndexNew;
        totalBorrows = totalBorrowsNew;
        totalReserves = totalReservesNew;

        /* We emit an AccrueInterest event */
        emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Sender supplies assets into the market and receives cTokens in exchange
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param mintAmount The amount of the underlying asset to supply
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
     */
    function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);
        }
        // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to
        return mintFresh(msg.sender, mintAmount);
    }

    struct MintLocalVars {
        Error err;
        MathError mathErr;
        uint exchangeRateMantissa;
        uint mintTokens;
        uint totalSupplyNew;
        uint accountTokensNew;
        uint actualMintAmount;
    }

    /**
     * @notice User supplies assets into the market and receives cTokens in exchange
     * @dev Assumes interest has already been accrued up to the current block
     * @param minter The address of the account which is supplying the assets
     * @param mintAmount The amount of the underlying asset to supply
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
     */
    function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {
        /* Fail if mint not allowed */
        uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);
        if (allowed != 0) {
            return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), 0);
        }

        MintLocalVars memory vars;

        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
        if (vars.mathErr != MathError.NO_ERROR) {
            return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         *  We call `doTransferIn` for the minter and the mintAmount.
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  `doTransferIn` reverts if anything goes wrong, since we can't be sure if
         *  side-effects occurred. The function returns the amount actually transferred,
         *  in case of a fee. On success, the cToken holds an additional `actualMintAmount`
         *  of cash.
         */
        vars.actualMintAmount = doTransferIn(minter, mintAmount);

        /*
         * We get the current exchange rate and calculate the number of cTokens to be minted:
         *  mintTokens = actualMintAmount / exchangeRate
         */

        (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));
        require(vars.mathErr == MathError.NO_ERROR, "MINT_EXCHANGE_CALCULATION_FAILED");

        /*
         * We calculate the new total supply of cTokens and minter token balance, checking for overflow:
         *  totalSupplyNew = totalSupply + mintTokens
         *  accountTokensNew = accountTokens[minter] + mintTokens
         */
        (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);
        require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED");

        (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);
        require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED");

        /* We write previously calculated values into storage */
        totalSupply = vars.totalSupplyNew;
        accountTokens[minter] = vars.accountTokensNew;

        /* We emit a Mint event, and a Transfer event */
        emit Mint(minter, vars.actualMintAmount, vars.mintTokens);
        emit Transfer(address(this), minter, vars.mintTokens);

        /* We call the defense hook */
        // unused function
        comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);

        return (uint(Error.NO_ERROR), vars.actualMintAmount);
    }

    /**
     * @notice Sender redeems cTokens in exchange for the underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemTokens The number of cTokens to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
            return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
        }
        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        return redeemFresh(msg.sender, redeemTokens, 0);
    }

    /**
     * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The amount of underlying to receive from redeeming cTokens
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
            return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
        }
        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        return redeemFresh(msg.sender, 0, redeemAmount);
    }

    struct RedeemLocalVars {
        Error err;
        MathError mathErr;
        uint exchangeRateMantissa;
        uint redeemTokens;
        uint redeemAmount;
        uint totalSupplyNew;
        uint accountTokensNew;
    }

    /**
     * @notice User redeems cTokens in exchange for the underlying asset
     * @dev Assumes interest has already been accrued up to the current block
     * @param redeemer The address of the account which is redeeming the tokens
     * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {
        require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");

        RedeemLocalVars memory vars;

        /* exchangeRate = invoke Exchange Rate Stored() */
        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));
        }

        /* If redeemTokensIn > 0: */
        if (redeemTokensIn > 0) {
            /*
             * We calculate the exchange rate and the amount of underlying to be redeemed:
             *  redeemTokens = redeemTokensIn
             *  redeemAmount = redeemTokensIn x exchangeRateCurrent
             */
            vars.redeemTokens = redeemTokensIn;

            (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));
            }
        } else {
            /*
             * We get the current exchange rate and calculate the amount to be redeemed:
             *  redeemTokens = redeemAmountIn / exchangeRate
             *  redeemAmount = redeemAmountIn
             */

            (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));
            }

            vars.redeemAmount = redeemAmountIn;
        }

        /* Fail if redeem not allowed */
        uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);
        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDEEM_FRESHNESS_CHECK);
        }

        /*
         * We calculate the new total supply and redeemer balance, checking for underflow:
         *  totalSupplyNew = totalSupply - redeemTokens
         *  accountTokensNew = accountTokens[redeemer] - redeemTokens
         */
        (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));
        }

        (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        /* Fail gracefully if protocol has insufficient cash */
        if (getCashPrior() < vars.redeemAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We invoke doTransferOut for the redeemer and the redeemAmount.
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the cToken has redeemAmount less of cash.
         *  doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
         */
        doTransferOut(redeemer, vars.redeemAmount);

        /* We write previously calculated values into storage */
        totalSupply = vars.totalSupplyNew;
        accountTokens[redeemer] = vars.accountTokensNew;

        /* We emit a Transfer event, and a Redeem event */
        emit Transfer(redeemer, address(this), vars.redeemTokens);
        emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);

        /* We call the defense hook */
        comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Sender borrows assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrowInternal(uint borrowAmount) internal nonReentrant returns (uint) {
        uint error = accrueInterest();

        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);
        }
        // borrowFresh emits borrow-specific logs on errors, so we don't need to
        return borrowFresh(msg.sender, borrowAmount);
    }

    struct BorrowLocalVars {
        MathError mathErr;
        uint accountBorrows;
        uint accountBorrowsNew;
        uint totalBorrowsNew;
    }

    /**
      * @notice Users borrow assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
        /* Fail if borrow not allowed */
        uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);

        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed);
        }


        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK);
        }

        /* Fail gracefully if protocol has insufficient underlying cash */
        if (getCashPrior() < borrowAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE);
        }

        BorrowLocalVars memory vars;

        /*
         * We calculate the new borrower and total borrow balances, failing on overflow:
         *  accountBorrowsNew = accountBorrows + borrowAmount
         *  totalBorrowsNew = totalBorrows + borrowAmount
         */
        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, borrowAmount);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We invoke doTransferOut for the borrower and the borrowAmount.
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the cToken borrowAmount less of cash.
         *  doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
         */
        doTransferOut(borrower, borrowAmount);

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        /* We emit a Borrow event */
        emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);

        /* We call the defense hook */
        // unused function
        // Comptroller.borrowVerify(address(this), borrower, borrowAmount);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Sender repays their own borrow
     * @param repayAmount The amount to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function repayBorrowInternal(uint repayAmount) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return (fail(Error(error), FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED), 0);
        }
        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        return repayBorrowFresh(msg.sender, msg.sender, repayAmount);
    }

    /**
     * @notice Sender repays a borrow belonging to borrower
     * @param borrower the account with the debt being payed off
     * @param repayAmount The amount to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return (fail(Error(error), FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED), 0);
        }
        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        return repayBorrowFresh(msg.sender, borrower, repayAmount);
    }

    struct RepayBorrowLocalVars {
        Error err;
        MathError mathErr;
        uint repayAmount;
        uint borrowerIndex;
        uint accountBorrows;
        uint accountBorrowsNew;
        uint totalBorrowsNew;
        uint actualRepayAmount;
    }

    /**
     * @notice Borrows are repaid by another user (possibly the borrower).
     * @param payer the account paying off the borrow
     * @param borrower the account with the debt being payed off
     * @param repayAmount the amount of undelrying tokens being returned
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint, uint) {
        /* Fail if repayBorrow not allowed */
        uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);
        if (allowed != 0) {
            return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, allowed), 0);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.REPAY_BORROW_FRESHNESS_CHECK), 0);
        }

        RepayBorrowLocalVars memory vars;

        /* We remember the original borrowerIndex for verification purposes */
        vars.borrowerIndex = accountBorrows[borrower].interestIndex;

        /* We fetch the amount the borrower owes, with accumulated interest */
        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
        if (vars.mathErr != MathError.NO_ERROR) {
            return (failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0);
        }

        /* If repayAmount == -1, repayAmount = accountBorrows */
        if (repayAmount == uint(-1)) {
            vars.repayAmount = vars.accountBorrows;
        } else {
            vars.repayAmount = repayAmount;
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We call doTransferIn for the payer and the repayAmount
         *  Note: The cToken must handle variations between ERC-20 and ETH underlying.
         *  On success, the cToken holds an additional repayAmount of cash.
         *  doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
         *   it returns the amount actually transferred, in case of a fee.
         */
        vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);

        /*
         * We calculate the new borrower and total borrow balances, failing on underflow:
         *  accountBorrowsNew = accountBorrows - actualRepayAmount
         *  totalBorrowsNew = totalBorrows - actualRepayAmount
         */
        (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount);
        require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED");

        (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount);
        require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED");

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        /* We emit a RepayBorrow event */
        emit RepayBorrow(payer, borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);

        /* We call the defense hook */
        // unused function
        // Comptroller.repayBorrowVerify(address(this), payer, borrower, vars.actualRepayAmount, vars.borrowerIndex);

        return (uint(Error.NO_ERROR), vars.actualRepayAmount);
    }

    /**
     * @notice The sender liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this cToken to be liquidated
     * @param cTokenCollateral The market in which to seize collateral from the borrower
     * @param repayAmount The amount of the underlying borrowed asset to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
            return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED), 0);
        }

        error = cTokenCollateral.accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
            return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED), 0);
        }

        // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to
        return liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral);
    }

    /**
     * @notice The liquidator liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this cToken to be liquidated
     * @param liquidator The address repaying the borrow and seizing collateral
     * @param cTokenCollateral The market in which to seize collateral from the borrower
     * @param repayAmount The amount of the underlying borrowed asset to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal returns (uint, uint) {
        /* Fail if liquidate not allowed */
        uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount);
        if (allowed != 0) {
            return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, allowed), 0);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_FRESHNESS_CHECK), 0);
        }

        /* Verify cTokenCollateral market's block number equals current block number */
        if (cTokenCollateral.getAccrualBlockNumber() != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK), 0);
        }

        /* Fail if borrower = liquidator */
        if (borrower == liquidator) {
            return (fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER), 0);
        }

        /* Fail if repayAmount = 0 */
        if (repayAmount == 0) {
            return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO), 0);
        }

        /* Fail if repayAmount = -1 */
        if (repayAmount == uint(-1)) {
            return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX), 0);
        }


        /* Fail if repayBorrow fails */
        (uint repayBorrowError, uint actualRepayAmount) = repayBorrowFresh(liquidator, borrower, repayAmount);
        if (repayBorrowError != uint(Error.NO_ERROR)) {
            return (fail(Error(repayBorrowError), FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED), 0);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We calculate the number of collateral tokens that will be seized */
        (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), actualRepayAmount);
        require(amountSeizeError == uint(Error.NO_ERROR), "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");

        /* Revert if borrower collateral token balance < seizeTokens */
        require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH");

        // If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call
        uint seizeError;
        if (address(cTokenCollateral) == address(this)) {
            seizeError = seizeInternal(address(this), liquidator, borrower, seizeTokens);
        } else {
            seizeError = cTokenCollateral.seize(liquidator, borrower, seizeTokens);
        }

        /* Revert if seize tokens fails (since we cannot be sure of side effects) */
        require(seizeError == uint(Error.NO_ERROR), "token seizure failed");

        /* We emit a LiquidateBorrow event */
        emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens);

        /* We call the defense hook */
        // unused function
        // Comptroller.liquidateBorrowVerify(address(this), address(cTokenCollateral), liquidator, borrower, actualRepayAmount, seizeTokens);

        return (uint(Error.NO_ERROR), actualRepayAmount);
    }

    /**
     * @notice Transfers collateral tokens (this market) to the liquidator.
     * @dev Will fail unless called by another cToken during the process of liquidation.
     *  Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.
     * @param liquidator The account receiving seized collateral
     * @param borrower The account having collateral seized
     * @param seizeTokens The number of cTokens to seize
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) {
        return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);
    }

    /**
     * @notice Transfers collateral tokens (this market) to the liquidator.
     * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.
     *  Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.
     * @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)
     * @param liquidator The account receiving seized collateral
     * @param borrower The account having collateral seized
     * @param seizeTokens The number of cTokens to seize
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {
        /* Fail if seize not allowed */
        uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);
        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);
        }

        /* Fail if borrower = liquidator */
        if (borrower == liquidator) {
            return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);
        }

        MathError mathErr;
        uint borrowerTokensNew;
        uint liquidatorTokensNew;

        /*
         * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:
         *  borrowerTokensNew = accountTokens[borrower] - seizeTokens
         *  liquidatorTokensNew = accountTokens[liquidator] + seizeTokens
         */
        (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));
        }

        (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We write the previously calculated values into storage */
        accountTokens[borrower] = borrowerTokensNew;
        accountTokens[liquidator] = liquidatorTokensNew;

        /* Emit a Transfer event */
        emit Transfer(borrower, liquidator, seizeTokens);

        /* We call the defense hook */
        // Transfer verify is required here due to tokens being transferred, and have to keep the
        // ACC accounting in check
        // This works, because the 'borrower' has to be in this market. and so, the active collateral usage can either remain unchanged
        // (if the liquidator is also in the market) or reduce (if the liquidator is not in the market)
        comptroller.transferVerify(address(this), borrower, liquidator, seizeTokens);

        /* We call the defense hook */
        // unused function
        // Comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);

        return uint(Error.NO_ERROR);
    }


    /*** Admin Functions ***/

    /**
      * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @param newPendingAdmin New pending admin.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);
        }

        // Save current value, if any, for inclusion in log
        address oldPendingAdmin = pendingAdmin;

        // Store pendingAdmin with value newPendingAdmin
        pendingAdmin = newPendingAdmin;

        // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
      * @dev Admin function for pending admin to accept role and update admin
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _acceptAdmin() external returns (uint) {
        // Check caller is pendingAdmin and pendingAdmin ≠ address(0)
        if (msg.sender != pendingAdmin || msg.sender == address(0)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);
        }

        // Save current values for inclusion in log
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        // Store admin with value pendingAdmin
        admin = pendingAdmin;

        // Clear the pending value
        pendingAdmin = address(0);

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
      * OLA_ADDITIONS : Made internal and removes Admin check.
      * @notice Sets a new Comptroller for the market
      * @dev Admin function to set a new Comptroller
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setComptroller(ComptrollerInterface newComptroller) internal returns (uint) {
        ComptrollerInterface oldComptroller = comptroller;
        // Ensure invoke Comptroller.isComptroller() returns true
        require(newComptroller.isComptroller(), "marker method returned false");

        // Set market's Comptroller to newComptroller
        comptroller = newComptroller;

        // Emit NewComptroller(oldComptroller, newComptroller)
        emit NewComptroller(oldComptroller, newComptroller);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
      * @dev Admin function to accrue interest and set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed.
            return fail(Error(error), FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED);
        }
        // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to.
        return _setReserveFactorFresh(newReserveFactorMantissa);
    }

    /**
      * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)
      * @dev Admin function to set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK);
        }

        // Verify market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK);
        }

        // Check newReserveFactor ≤ maxReserveFactor
        if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
            return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);
        }

        // OLA_ADDITIONS :This constraint
        // Check newReserveFactor >= minReserveFactor
        if (newReserveFactorMantissa < reserveFactorMinMantissa) {
            return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);
        }

        uint oldReserveFactorMantissa = reserveFactorMantissa;
        reserveFactorMantissa = newReserveFactorMantissa;

        emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Accrues interest and reduces reserves by transferring to admin
     * @param reduceAmount Amount of reduction to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _reduceReserves(uint reduceAmount) external nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.
            return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED);
        }



        // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to.
        return _reduceReservesFresh(reduceAmount);
    }

    /**
     * @notice Reduces reserves by transferring to the LeN admin and to Ola bank their respective shares
     * @dev Requires fresh interest accrual
     * @param reduceAmount Amount of reduction to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {
        // totalReserves - reduceAmount
        uint totalReservesNew;

        // OLA_ADDITIONS : Allowing anyone to reduce reserves
        // Check caller is admin
        // if (msg.sender != admin) {
        //     return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK);
        // }

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK);
        }

        // Fail gracefully if protocol has insufficient underlying cash
        if (getCashPrior() < reduceAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE);
        }

        // Check reduceAmount ≤ reserves[n] (totalReserves)
        if (reduceAmount > totalReserves) {
            return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);
        }

        // OLA_ADDITIONS : Dividing the reduced amount between the Admin and Ola (+validations)
        //                 Important to notice that we have added Math calculations to this function.
        //                 Where as before, it only used pre-calculated numbers.
        MathError mathErr;
        uint adminPart;
        uint olaPart;
        uint olaReserveFactor = fetchOlaReserveFactorMantissa();
        address payable olaBankAddress = fetchOlaBankAddress();
        address payable adminBankAddress = fetchAdminBankAddress();

        // Calculate olaPart
        (mathErr, olaPart) = mulScalarTruncate(Exp({mantissa: olaReserveFactor}), reduceAmount);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDUCE_RESERVES_OLA_PART_CALCULATION_FAILED, uint(mathErr));
        }

        // Sanity check, should never be a problem in a well parameterized system
        if (olaPart >= reduceAmount) {
            return fail(Error.BAD_SYSTEM_PARAMS, FailureInfo.REDUCE_RESERVES_OLA_PART_CALCULATION_FAILED);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        // Calculate admin part
        adminPart = reduceAmount - olaPart;
        // We checked olaPart < reduceAmount above, so this should never revert.
        require(adminPart < reduceAmount, "reduce reserves unexpected adminPart underflow");

        totalReservesNew = totalReserves - reduceAmount;
        // We checked reduceAmount <= totalReserves above, so this should never revert.
        require(totalReservesNew <= totalReserves, "reduce reserves unexpected underflow");

        // Store reserves[n+1] = reserves[n] - reduceAmount
        totalReserves = totalReservesNew;

        // OLA_ADDITIONS : Transfer reserves to both admin and Ola bank addresses
        // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
        doTransferOut(adminBankAddress, adminPart);
        doTransferOut(olaBankAddress, olaPart);

        emit ReservesReduced(adminBankAddress, adminPart, olaBankAddress, olaPart, totalReservesNew);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh
     * @dev Admin function to accrue interest and update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed
            return fail(Error(error), FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED);
        }
        // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to.
        return _setInterestRateModelFresh(newInterestRateModel);
    }

    /**
     * @notice updates the interest rate model (*requires fresh interest accrual)
     * @dev Admin function to update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {

        // Used to store old model for use in the event that is emitted on success
        InterestRateModel oldInterestRateModel;

        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK);
        }

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK);
        }

        // Ensure interest rate model is an approved contracts
        RegistryForOToken registry = RegistryForOToken(comptroller.getRegistry());

        require(registry.isSupportedInterestRateModel(address(newInterestRateModel)), "Unapproved interest rate model");

        // Track the market's current interest rate model
        oldInterestRateModel = interestRateModel;

        // Ensure invoke newInterestRateModel.isInterestRateModel() returns true
        require(newInterestRateModel.isInterestRateModel(), "marker method returned false");

        // Set the interest rate model to newInterestRateModel
        interestRateModel = newInterestRateModel;

        // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)
        emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);

        return uint(Error.NO_ERROR);
    }

    /*** Safe Token ***/

    /**
     * @notice Gets balance of this contract in terms of the underlying
     * @dev This excludes the value of the current message, if any
     * @return The quantity of underlying owned by this contract
     */
    function getCashPrior() internal view returns (uint);

    /**
     * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.
     *  This may revert due to insufficient balance or insufficient allowance.
     */
    function doTransferIn(address from, uint amount) internal returns (uint);

    /**
     * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.
     *  If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.
     *  If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.
     */
    function doTransferOut(address payable to, uint amount) internal;

    /**
     * OLA_ADDITIONS: This function
     * @dev Returns the ola reserves factor.
     */
    function fetchOlaReserveFactorMantissa() internal pure returns (uint) {
        return olaReserveFactorMantissa;
    }

    /**
     * OLA_ADDITIONS: This function
     * @dev Fetches the ola bank address.
     */
    function fetchOlaBankAddress() internal returns (address payable) {
        return RegistryForOToken(comptroller.getRegistry()).olaBankAddress();
    }

    /**
     * OLA_ADDITIONS: This function
     * @dev Fetches the admin bank address.
     */
    function fetchAdminBankAddress() internal view returns (address payable) {
        return ComptrollerForOToken(address(comptroller)).adminBankAddress();
    }

    /*** Reentrancy Guard ***/

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     */
    modifier nonReentrant() {
        require(_notEntered, "re-entered");
        _notEntered = false;
        _;
        _notEntered = true; // get a gas-refund post-Istanbul
    }
}

Contract ABI

[{"inputs":[{"internalType":"contract ComptrollerInterface","name":"comptroller_","type":"address"},{"internalType":"contract InterestRateModel","name":"interestRateModel_","type":"address"},{"internalType":"uint256","name":"initialExchangeRateMantissa_","type":"uint256"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"address payable","name":"admin_","type":"address"},{"internalType":"bytes","name":"becomeImplementationData","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"ImplementationDidNotChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"cTokenCollateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ComptrollerInterface","name":"oldComptroller","type":"address"},{"indexed":false,"internalType":"contract ComptrollerInterface","name":"newComptroller","type":"address"}],"name":"NewComptroller","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"name":"NewImplementation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewMarketInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"adminPart","type":"uint256"},{"indexed":false,"internalType":"address","name":"olaBank","type":"address"},{"indexed":false,"internalType":"uint256","name":"olaPart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalReserves","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"ONativeDelegatorContractHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"comptroller","outputs":[{"internalType":"contract ComptrollerInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contractNameHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateToImplementation","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"delegateToViewImplementation","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAccrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isCToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"contract CTokenInterface","name":"cTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"mint","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"nativeCoinUnderlying","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"olaReserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"repayBorrow","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"repayBorrowBehalf","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract EIP20NonStandardInterface","name":"token","type":"address"}],"name":"sweepToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"allowResign","type":"bool"},{"internalType":"bytes","name":"becomeImplementationData","type":"bytes"}],"name":"updateImplementationFromRegistry","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620025543803806200255483398181016040526101008110156200003857600080fd5b8151602083015160408085015160608601805192519496939591949391820192846401000000008211156200006c57600080fd5b9083019060208201858111156200008257600080fd5b82516401000000008111828201881017156200009d57600080fd5b82525081516020918201929091019080838360005b83811015620000cc578181015183820152602001620000b2565b50505050905090810190601f168015620000fa5780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200011e57600080fd5b9083019060208201858111156200013457600080fd5b82516401000000008111828201881017156200014f57600080fd5b82525081516020918201929091019080838360005b838110156200017e57818101518382015260200162000164565b50505050905090810190601f168015620001ac5780820380516001836020036101000a031916815260200191505b50604081815260208301519083015160609093018051919593949293929184640100000000821115620001de57600080fd5b908301906020820185811115620001f457600080fd5b82516401000000008111828201881017156200020f57600080fd5b82525081516020918201929091019080838360005b838110156200023e57818101518382015260200162000224565b50505050905090810190601f1680156200026c5780820380516001836020036101000a031916815260200191505b506040818152600080546001600160a01b031916331781556f27a730ba34bb32a232b632b3b0ba37b960811b835281519283900360100183206004908155635ab1bd5360e01b845291519095506001600160a01b038e169450635ab1bd5393508183019260209290829003018186803b158015620002e957600080fd5b505afa158015620002fe573d6000803e3d6000fd5b505050506040513d60208110156200031557600080fd5b5051604080516f27a730ba34bb32a232b632b3b0ba37b960811b81528151908190036010018120635fa4cae760e01b82526001600160a01b038d81166004840152602483019190915291519190921691635fa4cae79160448083019260209291908290030181600087803b1580156200038d57600080fd5b505af1158015620003a2573d6000803e3d6000fd5b505050506040513d6020811015620003b957600080fd5b50516040516001600160a01b03808c1660248301908152908b166044830152606482018a905260ff871660c483015260c060848301908152895160e48401528951939450620005179385938e938e938e938e938e938e939092909160a481019161010490910190602088019080838360005b83811015620004455781810151838201526020016200042b565b50505050905090810190601f168015620004735780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015620004a85781810151838201526020016200048e565b50505050905090810190601f168015620004d65780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03908116632676306d60e21b179091529099506200055e16975050505050505050565b506200052f816000846001600160e01b036200062516565b5050600080546001600160a01b0319166001600160a01b03929092169190911790555062000851945050505050565b606060006060846001600160a01b0316846040518082805190602001908083835b60208310620005a05780518252601f1990920191602091820191016200057f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811462000602576040519150601f19603f3d011682016040523d82523d6000602084013e62000607565b606091505b509150915060008214156200061d573d60208201fd5b949350505050565b811562000667576040805160048152602481019091526020810180516001600160e01b0390811663153ab50560e01b179091526200066591906200082716565b505b826001600160a01b031663fe9c44ae6040518163ffffffff1660e01b815260040160206040518083038186803b158015620006a157600080fd5b505afa158015620006b6573d6000803e3d6000fd5b505050506040513d6020811015620006cd57600080fd5b50516200070f576040805162461bcd60e51b815260206004820152600b60248201526a4e6f742043546f6b656e7360a81b604482015290519081900360640190fd5b600380546001600160a01b038581166001600160a01b03198316179092556040516020602482018181528551604484015285519490931693620007e5938693909283926064909201919085019080838360005b838110156200077c57818101518382015260200162000762565b50505050905090810190601f168015620007aa5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03908116630adccee560e31b179091529093506200082716915050565b506003546040516001600160a01b03918216918316907fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a90600090a350505050565b6003546060906200084b906001600160a01b0316836001600160e01b036200055e16565b92915050565b611cf380620008616000396000f3fe60806040526004361061025c5760003560e01c80638694505611610144578063c37f68e2116100b6578063e9c714f21161007a578063e9c714f214610aab578063f2b3abbd14610ac0578063f851a44014610af3578063f8f9da2814610b08578063fca7820b14610b1d578063fe9c44ae14610b475761025c565b8063c37f68e21461099d578063c5ebeaec146109f6578063db006a7514610a20578063dd62ed3e14610a4a578063e597461914610a855761025c565b8063aae40a2a11610108578063aae40a2a1461084b578063ae9d70b014610879578063b2a02ff11461088e578063b71d1a0c146108d1578063bc3246d914610904578063bd6d894d146109885761025c565b806386945056146107a057806395dd9193146107b5578063991754d2146107e8578063a6afed95146107fd578063a9059cbb146108125761025c565b80633b1d21a2116101dd5780635fe3b567116101a15780635fe3b567146106da578063601a0bf1146106ef57806370a0823114610719578063721db5b11461074c57806373acee9814610761578063852a12e3146107765761025c565b80633b1d21a2146105e25780634487152f146105f7578063469ab1e3146106a85780634e4d9fea146106bd5780635c60da1b146106c55761025c565b80631be19560116102245780631be19560146104f357806323b872dd1461052657806326782247146105695780632f7034981461059a5780633af9e669146105af5761025c565b80630933c1ed1461031c578063095ea7b3146104425780631249c58b1461048f57806317bfdfbc14610499578063182df0f5146104de575b34156102995760405162461bcd60e51b8152600401808060200182810382526032815260200180611c8d6032913960400191505060405180910390fd5b6003546040516000916001600160a01b031690829036908083838082843760405192019450600093509091505080830381855af49150503d80600081146102fc576040519150601f19603f3d011682016040523d82523d6000602084013e610301565b606091505b505090506040513d6000823e818015610318573d82f35b3d82fd5b34801561032857600080fd5b506103cd6004803603602081101561033f57600080fd5b810190602081018135600160201b81111561035957600080fd5b82018360208201111561036b57600080fd5b803590602001918460018302840111600160201b8311171561038c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610b5c945050505050565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104075781810151838201526020016103ef565b50505050905090810190601f1680156104345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561044e57600080fd5b5061047b6004803603604081101561046557600080fd5b506001600160a01b038135169060200135610b7b565b604080519115158252519081900360200190f35b610497610bf2565b005b3480156104a557600080fd5b506104cc600480360360208110156104bc57600080fd5b50356001600160a01b0316610c27565b60408051918252519081900360200190f35b3480156104ea57600080fd5b506104cc610c99565b3480156104ff57600080fd5b506104976004803603602081101561051657600080fd5b50356001600160a01b0316610cf0565b34801561053257600080fd5b5061047b6004803603606081101561054957600080fd5b506001600160a01b03813581169160208101359091169060400135610d3f565b34801561057557600080fd5b5061057e610dbf565b604080516001600160a01b039092168252519081900360200190f35b3480156105a657600080fd5b5061057e610dce565b3480156105bb57600080fd5b506104cc600480360360208110156105d257600080fd5b50356001600160a01b0316610de6565b3480156105ee57600080fd5b506104cc610e38565b34801561060357600080fd5b506103cd6004803603602081101561061a57600080fd5b810190602081018135600160201b81111561063457600080fd5b82018360208201111561064657600080fd5b803590602001918460018302840111600160201b8311171561066757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610e6c945050505050565b3480156106b457600080fd5b506104cc61108b565b610497611091565b3480156106d157600080fd5b5061057e6110c3565b3480156106e657600080fd5b5061057e6110d2565b3480156106fb57600080fd5b506104cc6004803603602081101561071257600080fd5b50356110e1565b34801561072557600080fd5b506104cc6004803603602081101561073c57600080fd5b50356001600160a01b0316611128565b34801561075857600080fd5b506104cc61117a565b34801561076d57600080fd5b506104cc611186565b34801561078257600080fd5b506104cc6004803603602081101561079957600080fd5b50356111be565b3480156107ac57600080fd5b506104cc611205565b3480156107c157600080fd5b506104cc600480360360208110156107d857600080fd5b50356001600160a01b031661122d565b3480156107f457600080fd5b506104cc61127f565b34801561080957600080fd5b506104cc6112b7565b34801561081e57600080fd5b5061047b6004803603604081101561083557600080fd5b506001600160a01b0381351690602001356112ef565b6104976004803603604081101561086157600080fd5b506001600160a01b0381358116916020013516611345565b34801561088557600080fd5b506104cc61139e565b34801561089a57600080fd5b506104cc600480360360608110156108b157600080fd5b506001600160a01b038135811691602081013590911690604001356113d6565b3480156108dd57600080fd5b506104cc600480360360208110156108f457600080fd5b50356001600160a01b0316611434565b34801561091057600080fd5b5061047b6004803603604081101561092757600080fd5b813515159190810190604081016020820135600160201b81111561094a57600080fd5b82018360208201111561095c57600080fd5b803590602001918460018302840111600160201b8311171561097d57600080fd5b509092509050611486565b34801561099457600080fd5b506104cc6116c3565b3480156109a957600080fd5b506109d0600480360360208110156109c057600080fd5b50356001600160a01b03166116fb565b604080519485526020850193909352838301919091526060830152519081900360800190f35b348015610a0257600080fd5b506104cc60048036036020811015610a1957600080fd5b503561178d565b348015610a2c57600080fd5b506104cc60048036036020811015610a4357600080fd5b50356117d4565b348015610a5657600080fd5b506104cc60048036036040811015610a6d57600080fd5b506001600160a01b038135811691602001351661181b565b61049760048036036020811015610a9b57600080fd5b50356001600160a01b0316611875565b348015610ab757600080fd5b506104cc6118c1565b348015610acc57600080fd5b506104cc60048036036020811015610ae357600080fd5b50356001600160a01b03166118f9565b348015610aff57600080fd5b5061057e61194b565b348015610b1457600080fd5b506104cc61195a565b348015610b2957600080fd5b506104cc60048036036020811015610b4057600080fd5b5035611992565b348015610b5357600080fd5b5061047b6119d9565b600354606090610b75906001600160a01b0316836119de565b92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052600090606090610bd190610b5c565b9050808060200190516020811015610be857600080fd5b5051949350505050565b6040805160048152602481019091526020810180516001600160e01b0316631249c58b60e01b179052610c2490610b5c565b50565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166305eff7ef60e21b179052600090606090610c7990610b5c565b9050808060200190516020811015610c9057600080fd5b50519392505050565b6040805160048152602481019091526020810180516001600160e01b031663182df0f560e01b179052600090606090610cd190610e6c565b9050808060200190516020811015610ce857600080fd5b505191505090565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031662df0cab60e51b179052610d3b90610b5c565b5050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052600090606090610d9d90610b5c565b9050808060200190516020811015610db457600080fd5b505195945050505050565b6001546001600160a01b031681565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b0316633af9e66960e01b179052600090606090610c7990610b5c565b6040805160048152602481019091526020810180516001600160e01b0316631d8e90d160e11b179052600090606090610cd1905b606060006060306001600160a01b0316846040516024018080602001828103825283818151815260200191508051906020019080838360005b83811015610ebd578181015183820152602001610ea5565b50505050905090810190601f168015610eea5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b0316630933c1ed60e01b178152905182519295509350839250908083835b60208310610f455780518252601f199092019160209182019101610f26565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610fa5576040519150601f19603f3d011682016040523d82523d6000602084013e610faa565b606091505b50915091506000821415610fbf573d60208201fd5b808060200190516020811015610fd457600080fd5b8101908080516040519392919084600160201b821115610ff357600080fd5b90830190602082018581111561100857600080fd5b8251600160201b81118282018810171561102157600080fd5b82525081516020918201929091019080838360005b8381101561104e578181015183820152602001611036565b50505050905090810190601f16801561107b5780820380516001836020036101000a031916815260200191505b5060405250505092505050919050565b60045481565b6040805160048152602481019091526020810180516001600160e01b0316632726cff560e11b179052610c2490610b5c565b6003546001600160a01b031681565b6002546001600160a01b031681565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663601a0bf160e01b179052600090606090610c7990610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166370a0823160e01b179052600090606090610c7990610e6c565b6706f05b59d3b2000081565b6040805160048152602481019091526020810180516001600160e01b0316630e759dd360e31b179052600090606090610cd190610b5c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663852a12e360e01b179052600090606090610c7990610b5c565b604080516f27a730ba34bb32a232b632b3b0ba37b960811b8152905190819003601001902081565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166395dd919360e01b179052600090606090610c7990610e6c565b6040805160048152602481019091526020810180516001600160e01b0316634c8baa6960e11b179052600090606090610cd190610e6c565b6040805160048152602481019091526020810180516001600160e01b031663a6afed9560e01b179052600090606090610cd190610b5c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052600090606090610bd190610b5c565b604080516001600160a01b03808516602483015283166044808301919091528251808303909101815260649091019091526020810180516001600160e01b0316635572051560e11b17905261139990610b5c565b505050565b6040805160048152602481019091526020810180516001600160e01b0316630ae9d70b60e41b179052600090606090610cd190610e6c565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b031663b2a02ff160e01b179052600090606090610d9d90610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b0316632dc7468360e21b179052600090606090610c7990610b5c565b6002546000906001600160a01b031633146114da576040805162461bcd60e51b815260206004820152600f60248201526e2737ba1031b7b6b83a3937b63632b960891b604482015290519081900360640190fd5b60025460408051635ab1bd5360e01b815290516000926001600160a01b031691635ab1bd53916004808301926020929190829003018186803b15801561151f57600080fd5b505afa158015611533573d6000803e3d6000fd5b505050506040513d602081101561154957600080fd5b50516002546004805460408051635fa4cae760e01b81526001600160a01b03948516938101939093526024830191909152519190921691635fa4cae79160448083019260209291908290030181600087803b1580156115a757600080fd5b505af11580156115bb573d6000803e3d6000fd5b505050506040513d60208110156115d157600080fd5b505190506001600160a01b038116611624576040805162461bcd60e51b815260206004820152601160248201527027379034b6b83632b6b2b73a30ba34b7b760791b604482015290519081900360640190fd5b6003546001600160a01b0382811691161461167f5761167a818686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611aa092505050565b6116b8565b6003546040516001600160a01b03909116907f4c1be6dd39236a8e070692d274dd5d9c6893e79d76431a2600b41b182a5c2fc290600090a25b506001949350505050565b6040805160048152602481019091526020810180516001600160e01b031663bd6d894d60e01b179052600090606090610cd190610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166361bfb47160e11b17905260009081908190819060609061175390610e6c565b905080806020019051608081101561176a57600080fd5b508051602082015160408301516060909301519199909850919650945092505050565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663317afabb60e21b179052600090606090610c7990610b5c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663db006a7560e01b179052600090606090610c7990610b5c565b604080516001600160a01b03808516602483015283166044808301919091528251808303909101815260649091019091526020810180516001600160e01b0316636eb1769f60e11b179052600090606090610bd190610e6c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031663e597461960e01b179052610d3b90610b5c565b6040805160048152602481019091526020810180516001600160e01b03166374e38a7960e11b179052600090606090610cd190610b5c565b604080516001600160a01b0383166024808301919091528251808303909101815260449091019091526020810180516001600160e01b031663f2b3abbd60e01b179052600090606090610c7990610b5c565b6000546001600160a01b031681565b6040805160048152602481019091526020810180516001600160e01b0316631f1f3b4560e31b179052600090606090610cd190610e6c565b6040805160248082018490528251808303909101815260449091019091526020810180516001600160e01b031663fca7820b60e01b179052600090606090610c7990610b5c565b600181565b606060006060846001600160a01b0316846040518082805190602001908083835b60208310611a1e5780518252601f1990920191602091820191016119ff565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114611a7e576040519150601f19603f3d011682016040523d82523d6000602084013e611a83565b606091505b50915091506000821415611a98573d60208201fd5b949350505050565b8115611ada576040805160048152602481019091526020810180516001600160e01b031663153ab50560e01b179052611ad890610b5c565b505b826001600160a01b031663fe9c44ae6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1357600080fd5b505afa158015611b27573d6000803e3d6000fd5b505050506040513d6020811015611b3d57600080fd5b5051611b7e576040805162461bcd60e51b815260206004820152600b60248201526a4e6f742043546f6b656e7360a81b604482015290519081900360640190fd5b600380546001600160a01b038581166001600160a01b03198316179092556040516020602482018181528551604484015285519490931693611c4a938693909283926064909201919085019080838360005b83811015611be8578181015183820152602001611bd0565b50505050905090810190601f168015611c155780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b0316630adccee560e31b1790529250610b5c915050565b506003546040516001600160a01b03918216918316907fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a90600090a35050505056fe4f44656c656761746f723a66616c6c6261636b3a2063616e6e6f742073656e642076616c756520746f2066616c6c6261636ba265627a7a7231582004f98f1715397a84d65c3eede9b284823a1cfeb84c69682ee0f9f3b4a0973a2064736f6c63430005100032000000000000000000000000dbb6b59a58cedaec2eeac4a889d3329ea9fdd8e6000000000000000000000000d64c3186a9c6ae6c1e92a110f76ab86f4c6295f9000000000000000000000000000000000000000000a56fa5b99019a5c8000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d950000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000b4f6c6120476c696d6d657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056f474c4d520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000dbb6b59a58cedaec2eeac4a889d3329ea9fdd8e6000000000000000000000000d64c3186a9c6ae6c1e92a110f76ab86f4c6295f9000000000000000000000000000000000000000000a56fa5b99019a5c8000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d950000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000b4f6c6120476c696d6d657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056f474c4d520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : comptroller_ (address): 0xdbb6b59a58cedaec2eeac4a889d3329ea9fdd8e6
Arg [1] : interestRateModel_ (address): 0xd64c3186a9c6ae6c1e92a110f76ab86f4c6295f9
Arg [2] : initialExchangeRateMantissa_ (uint256): 200000000000000000000000000
Arg [3] : name_ (string): Ola Glimmer
Arg [4] : symbol_ (string): oGLMR
Arg [5] : decimals_ (uint8): 8
Arg [6] : admin_ (address): 0xc333a03e8040cad31993e02615fd1b3f88447d95
Arg [7] : becomeImplementationData (bytes): 0x

-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 000000000000000000000000dbb6b59a58cedaec2eeac4a889d3329ea9fdd8e6
Arg [1] : 000000000000000000000000d64c3186a9c6ae6c1e92a110f76ab86f4c6295f9
Arg [2] : 000000000000000000000000000000000000000000a56fa5b99019a5c8000000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [6] : 000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d95
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [8] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [9] : 4f6c6120476c696d6d6572000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [11] : 6f474c4d52000000000000000000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000000


Deployed ByteCode Sourcemap

54067:17754:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53395:9;:14;53387:76;;;;-1:-1:-1;;;53387:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53562:14;;:37;;53544:12;;-1:-1:-1;;;;;53562:14:0;;53544:12;;53590:8;;53562:37;53544:12;53590:8;;53544:12;53562:37;1:33:-1;53562:37:0;;45:16:-1;;;-1:-1;53562:37:0;;-1:-1:-1;53562:37:0;;-1:-1:-1;;53562:37:0;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;53543:56:0;;;53662:4;53656:11;53713:14;53710:1;53696:12;53681:47;53751:7;53772:47;;;;53864:14;53850:12;53843:36;53772:47;53802:14;53788:12;53781:36;51367:141;;8:9:-1;5:2;;;30:1;27;20:12;5:2;51367:141:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;51367:141:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;51367:141:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;51367:141:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;51367:141:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;51367:141:0;;-1:-1:-1;51367:141:0;;-1:-1:-1;;;;;51367:141:0:i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;51367:141:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61189:249;;8:9:-1;5:2;;;30:1;27;20:12;5:2;61189:249:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;61189:249:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;56687:111;;;:::i;:::-;;65000:243;;8:9:-1;5:2;;;30:1;27;20:12;5:2;65000:243:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;65000:243:0;-1:-1:-1;;;;;65000:243:0;;:::i;:::-;;;;;;;;;;;;;;;;66312:215;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66312:215:0;;;:::i;68764:160::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;68764:160:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;68764:160:0;-1:-1:-1;;;;;68764:160:0;;:::i;60442:277::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;60442:277:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;60442:277:0;;;;;;;;;;;;;;;;;:::i;35957:35::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35957:35:0;;;:::i;:::-;;;;-1:-1:-1;;;;;35957:35:0;;;;;;;;;;;;;;40160:98;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40160:98:0;;;:::i;62700:237::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;62700:237:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;62700:237:0;-1:-1:-1;;;;;62700:237:0;;:::i;66697:195::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;66697:195:0;;;:::i;51930:434::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;51930:434:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;51930:434:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;51930:434:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;51930:434:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;51930:434:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;51930:434:0;;-1:-1:-1;51930:434:0;;-1:-1:-1;;;;;51930:434:0:i;36287:31::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36287:31:0;;;:::i;58570:125::-;;;:::i;36206:29::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36206:29:0;;;:::i;36083:39::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36083:39:0;;;:::i;70930:240::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;70930:240:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;70930:240:0;;:::i;62218:226::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;62218:226:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;62218:226:0;-1:-1:-1;;;;;62218:226:0;;:::i;40419:54::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40419:54:0;;;:::i;64499:210::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64499:210:0;;;:::i;57727:242::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57727:242:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;57727:242:0;;:::i;54197:84::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54197:84:0;;;:::i;65452:248::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;65452:248:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;65452:248:0;-1:-1:-1;;;;;65452:248:0;;:::i;67019:223::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;67019:223:0;;;:::i;67498:198::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;67498:198:0;;;:::i;59895:240::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59895:240:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;59895:240:0;;;;;;;;:::i;59408:226::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;59408:226:0;;;;;;;;;;:::i;64136:217::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64136:217:0;;;:::i;68257:294::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;68257:294:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;68257:294:0;;;;;;;;;;;;;;;;;:::i;69373:259::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;69373:259:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;69373:259:0;-1:-1:-1;;;;;69373:259:0;;:::i;52372:780::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52372:780:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;52372:780:0;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;52372:780:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;52372:780:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;-1:-1;;;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;-1:-1;52372:780:0;;-1:-1:-1;52372:780:0;-1:-1:-1;52372:780:0;:::i;65854:208::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;65854:208:0;;;:::i;63283:284::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;63283:284:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;63283:284:0;-1:-1:-1;;;;;63283:284:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58237:222;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58237:222:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;58237:222:0;;:::i;57149:::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57149:222:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;57149:222:0;;:::i;61768:260::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;61768:260:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;61768:260:0;;;;;;;;;;:::i;58886:170::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;58886:170:0;-1:-1:-1;;;;;58886:170:0;;:::i;70481:196::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;70481:196:0;;;:::i;71539:279::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;71539:279:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;71539:279:0;-1:-1:-1;;;;;71539:279:0;;:::i;35846:28::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35846:28:0;;;:::i;63743:217::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;63743:217:0;;;:::i;69935:268::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;69935:268:0;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;69935:268:0;;:::i;40574:36::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40574:36:0;;;:::i;51367:141::-;51479:14;;51436:12;;51468:32;;-1:-1:-1;;;;;51479:14:0;51495:4;51468:10;:32::i;:::-;51461:39;51367:141;-1:-1:-1;;51367:141:0:o;61189:249::-;61319:68;;;-1:-1:-1;;;;;61319:68:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;61319:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;61257:4:0;;61274:17;;61294:94;;:24;:94::i;:::-;61274:114;;61417:4;61406:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;61406:24:0;;61189:249;-1:-1:-1;;;;61189:249:0:o;56687:111::-;56756:33;;;22:32:-1;6:49;;56756:33:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;56731:59:0;;:24;:59::i;:::-;;56687:111::o;65000:243::-;65127:65;;;-1:-1:-1;;;;;65127:65:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;65127:65:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;65065:4:0;;65082:17;;65102:91;;:24;:91::i;:::-;65082:111;;65222:4;65211:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;65211:24:0;;65000:243;-1:-1:-1;;;65000:243:0:o;66312:215::-;66429:47;;;22:32:-1;6:49;;66429:47:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;66363:4:0;;66380:17;;66400:77;;:28;:77::i;:::-;66380:97;;66506:4;66495:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;66495:24:0;;-1:-1:-1;;66312:215:0;:::o;68764:160::-;68862:53;;;-1:-1:-1;;;;;68862:53:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;68862:53:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;68837:79:0;;:24;:79::i;:::-;;68764:160;:::o;60442:277::-;60586:82;;;-1:-1:-1;;;;;60586:82:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;60586:82:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;60524:4:0;;60541:17;;60561:108;;:24;:108::i;:::-;60541:128;;60698:4;60687:24;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;60687:24:0;;60442:277;-1:-1:-1;;;;;60442:277:0:o;35957:35::-;;;-1:-1:-1;;;;;35957:35:0;;:::o;40160:98::-;40215:42;40160:98;:::o;62700:237::-;62824:62;;;-1:-1:-1;;;;;62824:62:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;62824:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;62762:4:0;;62779:17;;62799:88;;:24;:88::i;66697:195::-;66805:36;;;22:32:-1;6:49;;66805:36:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;66739:4:0;;66756:17;;66776:66;;51930:434;52008:12;52034;52048:23;52083:4;-1:-1:-1;;;;;52075:24:0;52159:4;52100:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;52100:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52100:64:0;;;-1:-1:-1;;26:21;;;22:32;6:49;;52100:64:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;52075:90:0;;;;52100:64;;-1:-1:-1;52075:90:0;-1:-1:-1;52075:90:0;;-1:-1:-1;25:18;52075:90:0;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;52075:90:0;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;52033:132:0;;;;52215:1;52206:7;52203:14;52200:2;;;52267:14;52260:4;52248:10;52244:21;52237:45;52200:2;52336:10;52325:31;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;52325:31:0;;;;;;;;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;52325:31:0;;420:4:-1;411:14;;;;52325:31:0;;;;;411:14:-1;52325:31:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;52325:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52318:38;;;;51930:434;;;:::o;36287:31::-;;;;:::o;58570:125::-;58646:40;;;22:32:-1;6:49;;58646:40:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;58621:66:0;;:24;:66::i;36206:29::-;;;-1:-1:-1;;;;;36206:29:0;;:::o;36083:39::-;;;-1:-1:-1;;;;;36083:39:0;;:::o;70930:240::-;71054:65;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;71054:65:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;70992:4:0;;71009:17;;71029:91;;:24;:91::i;62218:226::-;62341:52;;;-1:-1:-1;;;;;62341:52:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;62341:52:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;62275:4:0;;62292:17;;62312:82;;:28;:82::i;40419:54::-;40467:6;40419:54;:::o;64499:210::-;64610:48;;;22:32:-1;6:49;;64610:48:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;64548:4:0;;64565:17;;64585:74;;:24;:74::i;57727:242::-;57852:66;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;57852:66:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;57790:4:0;;57807:17;;57827:92;;:24;:92::i;54197:84::-;54252:29;;;-1:-1:-1;;;54252:29:0;;;;;;;;;;;;54197:84;:::o;65452:248::-;65585:64;;;-1:-1:-1;;;;;65585:64:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;65585:64:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;65519:4:0;;65536:17;;65556:94;;:28;:94::i;67019:223::-;67141:50;;;22:32:-1;6:49;;67141:50:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;67075:4:0;;67092:17;;67112:80;;:28;:80::i;67498:198::-;67602:43;;;22:32:-1;6:49;;67602:43:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;67540:4:0;;67557:17;;67577:69;;:24;:69::i;59895:240::-;60019:65;;;-1:-1:-1;;;;;60019:65:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;60019:65:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;59957:4:0;;59974:17;;59994:91;;:24;:91::i;59408:226::-;59538:87;;;-1:-1:-1;;;;;59538:87:0;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;59538:87:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;59513:113:0;;:24;:113::i;:::-;;59408:226;;:::o;64136:217::-;64255:47;;;22:32:-1;6:49;;64255:47:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;64189:4:0;;64206:17;;64226:77;;:28;:77::i;68257:294::-;68408:92;;;-1:-1:-1;;;;;68408:92:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;68408:92:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;68346:4:0;;68363:17;;68383:118;;:24;:118::i;69373:259::-;69512:69;;;-1:-1:-1;;;;;69512:69:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;69512:69:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;69450:4:0;;69467:17;;69487:95;;:24;:95::i;52372:780::-;52538:11;;52491:4;;-1:-1:-1;;;;;52538:11:0;52516:10;:34;52508:62;;;;;-1:-1:-1;;;52508:62:0;;;;;;;;;;;;-1:-1:-1;;;52508:62:0;;;;;;;;;;;;;;;52633:11;;:25;;;-1:-1:-1;;;52633:25:0;;;;52581:27;;-1:-1:-1;;;;;52633:11:0;;:23;;:25;;;;;;;;;;;;;;:11;:25;;;5:2:-1;;;;30:1;27;20:12;5:2;52633:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;52633:25:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52633:25:0;52691:11;;52705:16;;;52611:111;;;-1:-1:-1;;;52611:111:0;;-1:-1:-1;;;;;52691:11:0;;;52611:111;;;;;;;;;;;;;;;:71;;;;;;;:111;;;;;52633:25;;52611:111;;;;;;;52691:11;52611:71;:111;;;5:2:-1;;;;30:1;27;20:12;5:2;52611:111:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;52611:111:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;52611:111:0;;-1:-1:-1;;;;;;52741:33:0;;52733:63;;;;;-1:-1:-1;;;52733:63:0;;;;;;;;;;;;-1:-1:-1;;;52733:63:0;;;;;;;;;;;;;;;52836:14;;-1:-1:-1;;;;;52813:37:0;;;52836:14;;52813:37;52809:312;;52951:78;52970:19;52991:11;53004:24;;52951:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;52951:18:0;;-1:-1:-1;;;52951:78:0:i;:::-;52809:312;;;53094:14;;53067:42;;-1:-1:-1;;;;;53094:14:0;;;;53067:42;;53094:14;;53067:42;52809:312;-1:-1:-1;53140:4:0;;52372:780;-1:-1:-1;;;;52372:780:0:o;65854:208::-;65963:48;;;22:32:-1;6:49;;65963:48:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;65901:4:0;;65918:17;;65938:74;;:24;:74::i;63283:284::-;63435:63;;;-1:-1:-1;;;;;63435:63:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;63435:63:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;63351:4:0;;;;;;;;63386:17;;63406:93;;:28;:93::i;:::-;63386:113;;63528:4;63517:42;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;63517:42:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;63517:42:0;;-1:-1:-1;63517:42:0;-1:-1:-1;63283:284:0;-1:-1:-1;;;63283:284:0:o;58237:222::-;58352:56;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;58352:56:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;58290:4:0;;58307:17;;58327:82;;:24;:82::i;57149:222::-;57264:56;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;57264:56:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;57202:4:0;;57219:17;;57239:82;;:24;:82::i;61768:260::-;61908:69;;;-1:-1:-1;;;;;61908:69:0;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;61908:69:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;61842:4:0;;61859:17;;61879:99;;:28;:99::i;58886:170::-;58984:63;;;-1:-1:-1;;;;;58984:63:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;58984:63:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;58959:89:0;;:24;:89::i;70481:196::-;70585:41;;;22:32:-1;6:49;;70585:41:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;70523:4:0;;70540:17;;70560:67;;:24;:67::i;71539:279::-;71688:79;;;-1:-1:-1;;;;;71688:79:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;71688:79:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;71626:4:0;;71643:17;;71663:105;;:24;:105::i;35846:28::-;;;-1:-1:-1;;;;;35846:28:0;;:::o;63743:217::-;63862:47;;;22:32:-1;6:49;;63862:47:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;63796:4:0;;63813:17;;63833:77;;:28;:77::i;69935:268::-;70073:79;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;70073:79:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;70011:4:0;;70028:17;;70048:105;;:24;:105::i;40574:36::-;40606:4;40574:36;:::o;50722:343::-;50795:12;50821;50835:23;50862:6;-1:-1:-1;;;;;50862:19:0;50882:4;50862:25;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;50862:25:0;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;50820:67:0;;;;50937:1;50928:7;50925:14;50922:2;;;50989:14;50982:4;50970:10;50966:21;50959:45;50922:2;51047:10;50722:343;-1:-1:-1;;;;50722:343:0:o;49719:643::-;49853:11;49849:120;;;49906:50;;;22:32:-1;6:49;;49906:50:0;;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;49881:76:0;;:24;:76::i;:::-;;49849:120;50021:15;-1:-1:-1;;;;;50014:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;50014:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;50014:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;50014:34:0;50006:58;;;;;-1:-1:-1;;;50006:58:0;;;;;;;;;;;;-1:-1:-1;;;50006:58:0;;;;;;;;;;;;;;;50105:14;;;-1:-1:-1;;;;;50130:32:0;;;-1:-1:-1;;;;;;50130:32:0;;;;;;50202:81;;;;;;;;;;;;;;;;;50105:14;;;;;50177:107;;50258:24;;50202:81;;;;;;;;;;;;;;;;50077:25;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;50202:81:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50202:81:0;;;-1:-1:-1;;26:21;;;22:32;6:49;;50202:81:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;50202:81:0;-1:-1:-1;50177:24:0;;-1:-1:-1;;50177:107:0:i;:::-;-1:-1:-1;50339:14:0;;50302:52;;-1:-1:-1;;;;;50339:14:0;;;;50302:52;;;;;50339:14;;50302:52;49719:643;;;;:::o

Swarm Source

bzzr://04f98f1715397a84d65c3eede9b284823a1cfeb84c69682ee0f9f3b4a0973a20
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.