ETH Price: $2,470.24 (+0.87%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x61012060199326832024-05-23 12:48:11166 days ago1716468491IN
 Create: SecondaryRewarder
0 ETH0.024301516.62508397

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SecondaryRewarder

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 29 : SecondaryRewarder.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity =0.7.6;

import {GenericToken} from "../../internal/balances/protocols/GenericToken.sol";
import {IRewarder} from "../../../interfaces/notional/IRewarder.sol";
import {NotionalProxy} from "../../../interfaces/notional/NotionalProxy.sol";
import {IERC20} from "../../../interfaces/IERC20.sol";
import {IEIP20NonStandard} from "../../../interfaces/IEIP20NonStandard.sol";
import {Constants} from "../../global/Constants.sol";
import {SafeInt256} from "../../math/SafeInt256.sol";
import {SafeUint256} from "../../math/SafeUint256.sol";
import {FloatingPoint} from "../../math/FloatingPoint.sol";
import {MerkleProof} from "@openzeppelin/contracts/cryptography/MerkleProof.sol";

contract SecondaryRewarder is IRewarder {
    using SafeUint256 for uint256;
    using SafeInt256 for int256;

    NotionalProxy public immutable NOTIONAL;
    address public immutable override NTOKEN_ADDRESS;
    address public immutable REWARD_TOKEN;
    uint8 public immutable REWARD_TOKEN_DECIMALS;
    uint16 public immutable override CURRENCY_ID;

    /// @notice When a rewarder is detached, it converts to an airdrop contract using the
    /// this merkleRoot that is set.
    /// @dev Uses a single storage slot
    bytes32 public merkleRoot;

    /* Rest of storage variables are packed into 256 bits */
    /// @notice When true user needs to call contract directly to claim any rewards left
    bool public override detached;

    /// @notice Marks the timestamp when incentives will end. Will always be less than block.timestamp
    /// if detached is true.
    uint32 public endTime;

    /// @notice Last time the contract accumulated the reward
    uint32 public override lastAccumulatedTime;

    // The emission rate of REWARD_TOKEN in INTERNAL_TOKEN_PRECISION packed to uint56
    uint56 private packedEmissionRatePerYear;

    /// @notice Aggregate tokens accumulated per nToken at `lastAccumulateTime` 
    //  in INCENTIVE_ACCUMULATION_PRECISION
    uint128 public override accumulatedRewardPerNToken;

    /// @notice Reward debt per account stored in 18 decimals.
    mapping(address => uint128) public rewardDebtPerAccount;

    modifier onlyOwner() {
        require(msg.sender == NOTIONAL.owner(), "Only owner");
        _;
    }

    modifier onlyNotional() {
        require(msg.sender == address(NOTIONAL), "Only Notional");
        _;
    }

    constructor(
        NotionalProxy notional,
        uint16 currencyId,
        IERC20 incentive_token,
        uint128 _emissionRatePerYear, // in INTERNAL_TOKEN_PRECISION
        uint32 _endTime
    ) {
        NOTIONAL = notional;
        CURRENCY_ID = currencyId;
        NTOKEN_ADDRESS = notional.nTokenAddress(currencyId);
        REWARD_TOKEN = address(incentive_token);
        REWARD_TOKEN_DECIMALS = IERC20(address(incentive_token)).decimals();

        packedEmissionRatePerYear = FloatingPoint.packTo56Bits(_emissionRatePerYear);
        lastAccumulatedTime = uint32(block.timestamp);
        require(lastAccumulatedTime < _endTime, "Invalid End Time");
        endTime = _endTime;
    }

    /// @notice The emission rate of REWARD_TOKEN in INTERNAL_TOKEN_PRECISION
    function emissionRatePerYear() public view override returns(uint128) {
        return uint128(FloatingPoint.unpackFromBits(packedEmissionRatePerYear));
    }

    /// @notice Get amount of reward account can claim at specified block time, only called before rewarder is detached
    /// @param account address to get reward amount for
    /// @param blockTime block time at which to get reward amount
    function getAccountRewardClaim(address account, uint32 blockTime)
        external
        view
        override
        returns (uint256 rewardToClaim)
    {
        require(!detached, "Detached");
        require(lastAccumulatedTime <= blockTime, "Invalid block time");

        uint256 totalSupply = IERC20(NTOKEN_ADDRESS).totalSupply();
        uint256 nTokenBalance = IERC20(NTOKEN_ADDRESS).balanceOf(account);

        uint32 time = uint32(SafeInt256.min(blockTime, endTime));
        uint128 rewardsPerNToken = _getAccumulatedRewardPerToken(time, totalSupply);
        rewardToClaim = _calculateRewardToClaim(account, nTokenBalance, rewardsPerNToken);
    }

    /// @notice Get amount of reward still left for account to claim, only called after rewarder is detached
    /// and merkle root is set
    /// @param account address to get reward amount for
    /// @param nTokenBalanceAtDetach nToken balance of account at time of detachment
    /// @param proof merkle proof to prove account and nTokenBalanceAtDetach are in tree
    function getAccountRewardClaim(address account, uint256 nTokenBalanceAtDetach, bytes32[] calldata proof)
        external
        view
        override
        returns (uint256 rewardToClaim)
    {
        require(detached && merkleRoot != bytes32(0), "Not detached");

        _checkProof(account, nTokenBalanceAtDetach, proof);
        // no need to accumulate, it was already accumulated when rewarder was detached
        rewardToClaim = _calculateRewardToClaim(account, nTokenBalanceAtDetach, accumulatedRewardPerNToken);
    }

    /// @notice Set incentive emission rate and incentive period end time, called only in case emission
    /// rate or incentive period changes since it is already set at deploy time, only can be called before
    /// rewarder is detached
    /// @param _emissionRatePerYear emission rate per year in INTERNAL_TOKEN_PRECISION
    /// @param _endTime time in seconds when incentive period will end
    function setIncentiveEmissionRate(uint128 _emissionRatePerYear, uint32 _endTime) external onlyOwner {
        require(!detached, "Detached");
        uint256 totalSupply = IERC20(NTOKEN_ADDRESS).totalSupply();

        _accumulateRewardPerNToken(uint32(block.timestamp), totalSupply);

        packedEmissionRatePerYear = FloatingPoint.packTo56Bits(_emissionRatePerYear);
        // lastAccumulatedTime is at block.timestamp here, ensure that the end time is always
        // further in the future.
        require(lastAccumulatedTime < _endTime, "Invalid End Time");
        endTime = _endTime;

        emit RewardEmissionUpdate(FloatingPoint.unpackFromBits(packedEmissionRatePerYear), _endTime);
    }

    /// @notice Set merkle root, only called after rewarder is detached
    /// @param _merkleRoot merkle root of the tree that contains accounts and nToken balances at detach time
    function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
        require(_merkleRoot != bytes32(0), "Invalid");
        merkleRoot = _merkleRoot;
    }

    /// @notice Allows owner to recover any ERC20 or ETH mistakenly sent to this contract
    /// @param token address of the token to recover, in case of ETH pass address(0)
    /// @param amount amount to recover
    function recover(address token, uint256 amount) external onlyOwner {
        if (Constants.ETH_ADDRESS == token) {
            (bool status,) = msg.sender.call{value: amount}("");
            require(status);
        } else {
            GenericToken.safeTransferOut(token, msg.sender, amount);
        }
    }

    /// @dev Called from Notional system to detach rewarder when switching to a new rewarder or when incentive
    /// period is over, after this merkle tree of user nToken balances at detach time should be generated
    /// offline and merkle root uploaded to this contract
    function detach() external override onlyNotional {
        require(!detached, "Already detached");

        // accumulate for the last time if needed
        uint256 totalSupply = IERC20(NTOKEN_ADDRESS).totalSupply();
        _accumulateRewardPerNToken(uint32(block.timestamp), totalSupply);

        detached = true;
        packedEmissionRatePerYear = 0;

        if (block.timestamp < endTime) {
            endTime = uint32(block.timestamp);
        }

        emit RewardEmissionUpdate(0, endTime);
    }

    /// @notice Allows claiming rewards after rewarder has been detached
    /// @param account address to claim rewards for
    /// @param nTokenBalanceAtDetach nToken balance of account at time of detachment
    /// @param proof merkle proof to prove account and nTokenBalanceAtDetach are in tree
    function claimRewardsDirect(address account, uint256 nTokenBalanceAtDetach, bytes32[] calldata proof)
        external
        override
    {
        require(detached, "Not detached");

        _checkProof(account, nTokenBalanceAtDetach, proof);

        _claimRewards(account, nTokenBalanceAtDetach, nTokenBalanceAtDetach);
    }

    /// @notice Allows claiming rewards but only from Notional system, called on each nToken balance change
    /// @param account address to claim rewards for
    /// @param currencyId id number of the currency
    /// @param nTokenBalanceBefore account nToken balance before the change
    /// @param nTokenBalanceAfter account nToken balance after the change
    /// @param priorNTokenSupply total nToken supply before the change
    function claimRewards(
        address account,
        uint16 currencyId,
        uint256 nTokenBalanceBefore,
        uint256 nTokenBalanceAfter,
        uint256 priorNTokenSupply
    ) external override onlyNotional {
        require(!detached, "Detached");
        require(currencyId == CURRENCY_ID, "Wrong currency id");

        _accumulateRewardPerNToken(uint32(block.timestamp), priorNTokenSupply);
        _claimRewards(account, nTokenBalanceBefore, nTokenBalanceAfter);
    }

    function _claimRewards(address account, uint256 nTokenBalanceBefore, uint256 nTokenBalanceAfter) private {
        uint256 rewardToClaim = _calculateRewardToClaim(account, nTokenBalanceBefore, accumulatedRewardPerNToken);

        // Precision here is:
        //  nTokenBalanceAfter (INTERNAL_TOKEN_PRECISION)
        //  accumulatedRewardPerNToken (INCENTIVE_ACCUMULATION_PRECISION)
        // DIVIDE BY
        //  INTERNAL_TOKEN_PRECISION
        //  => INCENTIVE_ACCUMULATION_PRECISION (1e18)
        rewardDebtPerAccount[account] = nTokenBalanceAfter
            .mul(accumulatedRewardPerNToken)
            .div(uint256(Constants.INTERNAL_TOKEN_PRECISION))
            .toUint128();

        if (0 < rewardToClaim) {
            try IEIP20NonStandard(REWARD_TOKEN).transfer(account, rewardToClaim) {
                bool success = checkReturnCode();
                if (success) {
                    emit RewardTransfer(REWARD_TOKEN, account, rewardToClaim);
                }
            // ignore failed reward transfers
            } catch {}
        }
    }

    function _getAccumulatedRewardPerToken(uint32 time, uint256 totalSupply) private view returns (uint128) {
        uint256 additionalIncentiveAccumulatedPerNToken;
        if (lastAccumulatedTime < time && 0 < totalSupply) {
            // NOTE: no underflow, checked in if statement
            uint256 timeSinceLastAccumulation = time - lastAccumulatedTime;
            // Precision here is:
            //  timeSinceLastAccumulation (SECONDS)
            //  INCENTIVE_ACCUMULATION_PRECISION (1e18)
            //  INTERNAL_TOKEN_PRECISION (1e8)
            // DIVIDE BY
            //  YEAR (SECONDS)
            //  INTERNAL_TOKEN_PRECISION (1e8)
            // => Precision = INCENTIVE_ACCUMULATION_PRECISION * INTERNAL_TOKEN_PRECISION / INTERNAL_TOKEN_PRECISION
            // => 1e18
            additionalIncentiveAccumulatedPerNToken = timeSinceLastAccumulation
                .mul(Constants.INCENTIVE_ACCUMULATION_PRECISION)
                .mul(emissionRatePerYear())
                .div(Constants.YEAR)
                .div(totalSupply);
        }

        return uint256(accumulatedRewardPerNToken).add(additionalIncentiveAccumulatedPerNToken).toUint128();
    }

    function _accumulateRewardPerNToken(uint32 blockTime, uint256 totalSupply) private {
        // Ensure that end time is set to some value
        require(0 < endTime);
        uint32 time = uint32(SafeInt256.min(blockTime, endTime));

        accumulatedRewardPerNToken = _getAccumulatedRewardPerToken(time, totalSupply);

        lastAccumulatedTime = uint32(block.timestamp);
    }

    function _calculateRewardToClaim(address account, uint256 nTokenBalanceAtLastClaim, uint128 rewardsPerNToken)
        private
        view
        returns (uint256)
    {
        // Precision here is:
        //   nTokenBalanceAtLastClaim (INTERNAL_TOKEN_PRECISION)
        //   mul rewardsPerNToken (INCENTIVE_ACCUMULATION_PRECISION)
        //   div INTERNAL_TOKEN_PRECISION
        // => INCENTIVE_ACCUMULATION_PRECISION
        // SUB rewardDebtPerAccount (INCENTIVE_ACCUMULATION_PRECISION)
        //
        // - mul REWARD_TOKEN_DECIMALS
        // - div INCENTIVE_ACCUMULATION_PRECISION
        // => REWARD_TOKEN_DECIMALS
        return uint256(nTokenBalanceAtLastClaim)
            .mul(rewardsPerNToken)
            .div(uint256(Constants.INTERNAL_TOKEN_PRECISION))
            .sub(rewardDebtPerAccount[account])
            .mul(10 ** REWARD_TOKEN_DECIMALS)
            .div(Constants.INCENTIVE_ACCUMULATION_PRECISION);
    }

    /// @notice Verify merkle proof, or revert if not in tree
    function _checkProof(address account, uint256 balance, bytes32[] calldata proof) private view {
        // Verify merkle proof, or revert if not in tree
        bytes32 leaf = keccak256(abi.encodePacked(account, balance));
        bool isValidLeaf = MerkleProof.verify(proof, merkleRoot, leaf);
        require(isValidLeaf, "NotInMerkle");
    }

    function checkReturnCode() private pure returns(bool success) {
        uint256[1] memory result;
        assembly {
            switch returndatasize()
                case 0 {
                    // This is a non-standard ERC-20
                    success := 1 // set success to true
                }
                case 32 {
                    // This is a compliant ERC-20
                    returndatacopy(result, 0, 32)
                    success := mload(result) // Set `success = returndata` of external call
                }
                default {
                    // This is an excessively non-compliant ERC-20.
                    success := 0
                }
        }
    }
}

File 2 of 29 : MerkleProof.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev These functions deal with verification of Merkle trees (hash trees),
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        bytes32 computedHash = leaf;

        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];

            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }

        // Check if the computed hash (root) is equal to the provided root
        return computedHash == root;
    }
}

File 3 of 29 : Constants.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;

/// @title All shared constants for the Notional system should be declared here.
library Constants {
    uint8 internal constant CETH_DECIMAL_PLACES = 8;

    // Token precision used for all internal balances, TokenHandler library ensures that we
    // limit the dust amount caused by precision mismatches
    int256 internal constant INTERNAL_TOKEN_PRECISION = 1e8;
    uint256 internal constant INCENTIVE_ACCUMULATION_PRECISION = 1e18;

    // ETH will be initialized as the first currency
    uint256 internal constant ETH_CURRENCY_ID = 1;
    uint8 internal constant ETH_DECIMAL_PLACES = 18;
    int256 internal constant ETH_DECIMALS = 1e18;
    address internal constant ETH_ADDRESS = address(0);
    // Used to prevent overflow when converting decimal places to decimal precision values via
    // 10**decimalPlaces. This is a safe value for int256 and uint256 variables. We apply this
    // constraint when storing decimal places in governance.
    uint256 internal constant MAX_DECIMAL_PLACES = 36;

    // Address of the account where fees are collected
    address internal constant FEE_RESERVE = 0x0000000000000000000000000000000000000FEE;
    // Address of the account where settlement funds are collected, this is only
    // used for off chain event tracking.
    address internal constant SETTLEMENT_RESERVE = 0x00000000000000000000000000000000000005e7;

    // Most significant bit
    bytes32 internal constant MSB =
        0x8000000000000000000000000000000000000000000000000000000000000000;

    // Each bit set in this mask marks where an active market should be in the bitmap
    // if the first bit refers to the reference time. Used to detect idiosyncratic
    // fcash in the nToken accounts
    bytes32 internal constant ACTIVE_MARKETS_MASK = (
        MSB >> ( 90 - 1) | // 3 month
        MSB >> (105 - 1) | // 6 month
        MSB >> (135 - 1) | // 1 year
        MSB >> (147 - 1) | // 2 year
        MSB >> (183 - 1) | // 5 year
        MSB >> (211 - 1) | // 10 year
        MSB >> (251 - 1)   // 20 year
    );

    // Basis for percentages
    int256 internal constant PERCENTAGE_DECIMALS = 100;
    // Min Buffer Scale and Buffer Scale are used in ExchangeRate to increase the maximum
    // possible buffer values at the higher end of the uint8 range.
    int256 internal constant MIN_BUFFER_SCALE = 150;
    int256 internal constant BUFFER_SCALE = 10;
    // Max number of traded markets, also used as the maximum number of assets in a portfolio array
    uint256 internal constant MAX_TRADED_MARKET_INDEX = 7;
    // Max number of fCash assets in a bitmap, this is based on the gas costs of calculating free collateral
    // for a bitmap portfolio
    uint256 internal constant MAX_BITMAP_ASSETS = 20;
    uint256 internal constant FIVE_MINUTES = 300;

    // Internal date representations, note we use a 6/30/360 week/month/year convention here
    uint256 internal constant DAY = 86400;
    // We use six day weeks to ensure that all time references divide evenly
    uint256 internal constant WEEK = DAY * 6;
    uint256 internal constant MONTH = WEEK * 5;
    uint256 internal constant QUARTER = MONTH * 3;
    uint256 internal constant YEAR = QUARTER * 4;
    
    // These constants are used in DateTime.sol
    uint256 internal constant DAYS_IN_WEEK = 6;
    uint256 internal constant DAYS_IN_MONTH = 30;
    uint256 internal constant DAYS_IN_QUARTER = 90;

    // Offsets for each time chunk denominated in days
    uint256 internal constant MAX_DAY_OFFSET = 90;
    uint256 internal constant MAX_WEEK_OFFSET = 360;
    uint256 internal constant MAX_MONTH_OFFSET = 2160;
    uint256 internal constant MAX_QUARTER_OFFSET = 7650;

    // Offsets for each time chunk denominated in bits
    uint256 internal constant WEEK_BIT_OFFSET = 90;
    uint256 internal constant MONTH_BIT_OFFSET = 135;
    uint256 internal constant QUARTER_BIT_OFFSET = 195;

    // Number of decimal places that rates are stored in, equals 100%
    int256 internal constant RATE_PRECISION = 1e9;
    // Used for prime cash scalars
    uint256 internal constant SCALAR_PRECISION = 1e18;
    // Used in prime rate lib
    int256 internal constant DOUBLE_SCALAR_PRECISION = 1e36;
    // One basis point in RATE_PRECISION terms
    uint256 internal constant BASIS_POINT = uint256(RATE_PRECISION / 10000);
    // Used to when calculating the amount to deleverage of a market when minting nTokens
    uint256 internal constant DELEVERAGE_BUFFER = 300 * BASIS_POINT;
    // Used for scaling cash group factors
    uint256 internal constant FIVE_BASIS_POINTS = 5 * BASIS_POINT;
    // Used for residual purchase incentive and cash withholding buffer
    uint256 internal constant TEN_BASIS_POINTS = 10 * BASIS_POINT;
    // Used for max oracle rate
    uint256 internal constant FIFTEEN_BASIS_POINTS = 15 * BASIS_POINT;
    // Used in max rate calculations
    uint256 internal constant MAX_LOWER_INCREMENT = 150;
    uint256 internal constant MAX_LOWER_INCREMENT_VALUE = 150 * 25 * BASIS_POINT;
    uint256 internal constant TWENTY_FIVE_BASIS_POINTS = 25 * BASIS_POINT;
    uint256 internal constant ONE_HUNDRED_FIFTY_BASIS_POINTS = 150 * BASIS_POINT;

    // This is the ABDK64x64 representation of RATE_PRECISION
    // RATE_PRECISION_64x64 = ABDKMath64x64.fromUint(RATE_PRECISION)
    int128 internal constant RATE_PRECISION_64x64 = 0x3b9aca000000000000000000;

    uint8 internal constant FCASH_ASSET_TYPE          = 1;
    // Liquidity token asset types are 1 + marketIndex (where marketIndex is 1-indexed)
    uint8 internal constant MIN_LIQUIDITY_TOKEN_INDEX = 2;
    uint8 internal constant MAX_LIQUIDITY_TOKEN_INDEX = 8;
    uint8 internal constant VAULT_SHARE_ASSET_TYPE    = 9;
    uint8 internal constant VAULT_DEBT_ASSET_TYPE     = 10;
    uint8 internal constant VAULT_CASH_ASSET_TYPE     = 11;
    // Used for tracking legacy nToken assets
    uint8 internal constant LEGACY_NTOKEN_ASSET_TYPE  = 12;

    // Account context flags
    bytes1 internal constant HAS_ASSET_DEBT           = 0x01;
    bytes1 internal constant HAS_CASH_DEBT            = 0x02;
    bytes2 internal constant ACTIVE_IN_PORTFOLIO      = 0x8000;
    bytes2 internal constant ACTIVE_IN_BALANCES       = 0x4000;
    bytes2 internal constant UNMASK_FLAGS             = 0x3FFF;
    uint16 internal constant MAX_CURRENCIES           = uint16(UNMASK_FLAGS);

    // Equal to 100% of all deposit amounts for nToken liquidity across fCash markets.
    int256 internal constant DEPOSIT_PERCENT_BASIS    = 1e8;

    // nToken Parameters: there are offsets in the nTokenParameters bytes6 variable returned
    // in nTokenHandler. Each constant represents a position in the byte array.
    uint8 internal constant LIQUIDATION_HAIRCUT_PERCENTAGE = 0;
    uint8 internal constant CASH_WITHHOLDING_BUFFER = 1;
    uint8 internal constant RESIDUAL_PURCHASE_TIME_BUFFER = 2;
    uint8 internal constant PV_HAIRCUT_PERCENTAGE = 3;
    uint8 internal constant RESIDUAL_PURCHASE_INCENTIVE = 4;
    uint8 internal constant MAX_MINT_DEVIATION_LIMIT = 5;

    // Liquidation parameters
    // Default percentage of collateral that a liquidator is allowed to liquidate, will be higher if the account
    // requires more collateral to be liquidated
    int256 internal constant DEFAULT_LIQUIDATION_PORTION = 40;
    // Percentage of local liquidity token cash claim delivered to the liquidator for liquidating liquidity tokens
    int256 internal constant TOKEN_REPO_INCENTIVE_PERCENT = 30;

    // Pause Router liquidation enabled states
    bytes1 internal constant LOCAL_CURRENCY_ENABLED = 0x01;
    bytes1 internal constant COLLATERAL_CURRENCY_ENABLED = 0x02;
    bytes1 internal constant LOCAL_FCASH_ENABLED = 0x04;
    bytes1 internal constant CROSS_CURRENCY_FCASH_ENABLED = 0x08;

    // Requires vault accounts to enter a position for a minimum of 1 min
    // to mitigate strange behavior where accounts may enter and exit using
    // flash loans or other MEV type behavior.
    uint256 internal constant VAULT_ACCOUNT_MIN_TIME = 1 minutes;

    // Placeholder constant to mark the variable rate prime cash maturity
    uint40 internal constant PRIME_CASH_VAULT_MATURITY = type(uint40).max;

    // This represents the maximum percent change allowed before and after 
    // a rebalancing. 100_000 represents a 0.01% change
    // as a result of rebalancing. We should expect to never lose value as
    // a result of rebalancing, but some rounding errors may exist as a result
    // of redemption and deposit.
    int256 internal constant REBALANCING_UNDERLYING_DELTA_PERCENT = 100_000;

    // Ensures that the minimum total underlying held by the contract continues
    // to accrue interest so that money market oracle rates are properly updated
    // between rebalancing. With a minimum rebalancing cool down time of 6 hours
    // we would be able to detect at least 1 unit of accrual at 8 decimal precision
    // at an interest rate of 2.8 basis points (0.0288%) with 0.05e8 minimum balance
    // held in a given token.
    //
    //                          MIN_ACCRUAL * (86400 / REBALANCING_COOL_DOWN_HOURS)
    // MINIMUM_INTEREST_RATE =  ---------------------------------------------------
    //                                     MINIMUM_UNDERLYING_BALANCE
    int256 internal constant MIN_TOTAL_UNDERLYING_VALUE = 0.05e8;
}

File 4 of 29 : Deployments.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;

import {WETH9} from "../../interfaces/WETH9.sol";
import {IUpgradeableBeacon} from "../proxy/beacon/IBeacon.sol";
import {AggregatorV2V3Interface} from "../../interfaces/chainlink/AggregatorV2V3Interface.sol";

/// @title Hardcoded deployed contracts are listed here. These are hardcoded to reduce
/// gas costs for immutable addresses. They must be updated per environment that Notional
/// is deployed to.
library Deployments {
    uint256 internal constant MAINNET = 1;
    uint256 internal constant ARBITRUM_ONE = 42161;
    uint256 internal constant LOCAL = 1337;

    // MAINNET: 0xCFEAead4947f0705A14ec42aC3D44129E1Ef3eD5
    address internal constant NOTE_TOKEN_ADDRESS = 0xCFEAead4947f0705A14ec42aC3D44129E1Ef3eD5;
    // ARBITRUM: 0x019bE259BC299F3F653688c7655C87F998Bc7bC1
    // address internal constant NOTE_TOKEN_ADDRESS = 0x019bE259BC299F3F653688c7655C87F998Bc7bC1;

    // MAINNET: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
    WETH9 internal constant WETH = WETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    // ARBITRUM: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
    // WETH9 internal constant WETH = WETH9(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
    // OPTIMISM: 0x4200000000000000000000000000000000000006

    // Chainlink L2 Sequencer Uptime: https://docs.chain.link/data-feeds/l2-sequencer-feeds/
    // MAINNET: NOT SET
    AggregatorV2V3Interface internal constant SEQUENCER_UPTIME_ORACLE = AggregatorV2V3Interface(address(0));
    // ARBITRUM: 0xFdB631F5EE196F0ed6FAa767959853A9F217697D
    // AggregatorV2V3Interface internal constant SEQUENCER_UPTIME_ORACLE = AggregatorV2V3Interface(0xFdB631F5EE196F0ed6FAa767959853A9F217697D);

    enum BeaconType {
        NTOKEN,
        PCASH,
        PDEBT,
        WRAPPED_FCASH
    }

    // NOTE: these are temporary Beacon addresses
    IUpgradeableBeacon internal constant NTOKEN_BEACON = IUpgradeableBeacon(0xc4FD259b816d081C8bdd22D6bbd3495DB1573DB7);
    IUpgradeableBeacon internal constant PCASH_BEACON = IUpgradeableBeacon(0x1F681977aF5392d9Ca5572FB394BC4D12939A6A9);
    IUpgradeableBeacon internal constant PDEBT_BEACON = IUpgradeableBeacon(0xDF08039c0af34E34660aC7c2705C0Da953247640);
    // Mainnet:
    IUpgradeableBeacon internal constant WRAPPED_FCASH_BEACON = IUpgradeableBeacon(0xEBe1BF1653d55d31F6ED38B1A4CcFE2A92338f66);
    // Arbitrum:
    // IUpgradeableBeacon internal constant WRAPPED_FCASH_BEACON = IUpgradeableBeacon(0xD676d720E4e8B14F545F9116F0CAD47aF32329DD);
    

    // NOTE: this is unused and should be removed if the contract is ever deployed again
    uint256 internal constant NOTIONAL_V2_FINAL_SETTLEMENT = 0;
}

File 5 of 29 : Types.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import "../../interfaces/chainlink/AggregatorV2V3Interface.sol";
import "../../interfaces/notional/IPrimeCashHoldingsOracle.sol";
import "../../interfaces/notional/AssetRateAdapter.sol";

/// @notice Different types of internal tokens
///  - UnderlyingToken: underlying asset for a cToken (except for Ether)
///  - cToken: Compound interest bearing token
///  - cETH: Special handling for cETH tokens
///  - Ether: the one and only
///  - NonMintable: tokens that do not have an underlying (therefore not cTokens)
///  - aToken: Aave interest bearing tokens
enum TokenType {
    UnderlyingToken,
    cToken,
    cETH,
    Ether,
    NonMintable,
    aToken
}

/// @notice Specifies the different trade action types in the system. Each trade action type is
/// encoded in a tightly packed bytes32 object. Trade action type is the first big endian byte of the
/// 32 byte trade action object. The schemas for each trade action type are defined below.
enum TradeActionType {
    // (uint8 TradeActionType, uint8 MarketIndex, uint88 fCashAmount, uint32 minImpliedRate, uint120 unused)
    Lend,
    // (uint8 TradeActionType, uint8 MarketIndex, uint88 fCashAmount, uint32 maxImpliedRate, uint128 unused)
    Borrow,
    // (uint8 TradeActionType, uint8 MarketIndex, uint88 primeCashAmount, uint32 minImpliedRate, uint32 maxImpliedRate, uint88 unused)
    AddLiquidity,
    // (uint8 TradeActionType, uint8 MarketIndex, uint88 tokenAmount, uint32 minImpliedRate, uint32 maxImpliedRate, uint88 unused)
    RemoveLiquidity,
    // (uint8 TradeActionType, uint32 Maturity, int88 fCashResidualAmount, uint128 unused)
    PurchaseNTokenResidual,
    // (uint8 TradeActionType, address CounterpartyAddress, int88 fCashAmountToSettle)
    SettleCashDebt
}

/// @notice Specifies different deposit actions that can occur during BalanceAction or BalanceActionWithTrades
enum DepositActionType {
    // No deposit action
    None,
    // Deposit asset cash, depositActionAmount is specified in asset cash external precision
    DepositAsset,
    // Deposit underlying tokens that are mintable to asset cash, depositActionAmount is specified in underlying token
    // external precision
    DepositUnderlying,
    // Deposits specified asset cash external precision amount into an nToken and mints the corresponding amount of
    // nTokens into the account
    DepositAssetAndMintNToken,
    // Deposits specified underlying in external precision, mints asset cash, and uses that asset cash to mint nTokens
    DepositUnderlyingAndMintNToken,
    // Redeems an nToken balance to asset cash. depositActionAmount is specified in nToken precision. Considered a deposit action
    // because it deposits asset cash into an account. If there are fCash residuals that cannot be sold off, will revert.
    RedeemNToken,
    // Converts specified amount of asset cash balance already in Notional to nTokens. depositActionAmount is specified in
    // Notional internal 8 decimal precision.
    ConvertCashToNToken
}

/// @notice Used internally for PortfolioHandler state
enum AssetStorageState {
    NoChange,
    Update,
    Delete,
    RevertIfStored
}

/****** Calldata objects ******/

/// @notice Defines a batch lending action
struct BatchLend {
    uint16 currencyId;
    // True if the contract should try to transfer underlying tokens instead of asset tokens
    bool depositUnderlying;
    // Array of tightly packed 32 byte objects that represent trades. See TradeActionType documentation
    bytes32[] trades;
}

/// @notice Defines a balance action for batchAction
struct BalanceAction {
    // Deposit action to take (if any)
    DepositActionType actionType;
    uint16 currencyId;
    // Deposit action amount must correspond to the depositActionType, see documentation above.
    uint256 depositActionAmount;
    // Withdraw an amount of asset cash specified in Notional internal 8 decimal precision
    uint256 withdrawAmountInternalPrecision;
    // If set to true, will withdraw entire cash balance. Useful if there may be an unknown amount of asset cash
    // residual left from trading.
    bool withdrawEntireCashBalance;
    // If set to true, will redeem asset cash to the underlying token on withdraw.
    bool redeemToUnderlying;
}

/// @notice Defines a balance action with a set of trades to do as well
struct BalanceActionWithTrades {
    DepositActionType actionType;
    uint16 currencyId;
    uint256 depositActionAmount;
    uint256 withdrawAmountInternalPrecision;
    bool withdrawEntireCashBalance;
    bool redeemToUnderlying;
    // Array of tightly packed 32 byte objects that represent trades. See TradeActionType documentation
    bytes32[] trades;
}

/****** In memory objects ******/
/// @notice Internal object that represents settled cash balances
struct SettleAmount {
    uint16 currencyId;
    int256 positiveSettledCash;
    int256 negativeSettledCash;
    PrimeRate presentPrimeRate;
}

/// @notice Internal object that represents a token
struct Token {
    address tokenAddress;
    bool hasTransferFee;
    int256 decimals;
    TokenType tokenType;
    uint256 deprecated_maxCollateralBalance;
}

/// @notice Internal object that represents an nToken portfolio
struct nTokenPortfolio {
    CashGroupParameters cashGroup;
    PortfolioState portfolioState;
    int256 totalSupply;
    int256 cashBalance;
    uint256 lastInitializedTime;
    bytes6 parameters;
    address tokenAddress;
}

/// @notice Internal object used during liquidation
struct LiquidationFactors {
    address account;
    // Aggregate free collateral of the account denominated in ETH underlying, 8 decimal precision
    int256 netETHValue;
    // Amount of net local currency asset cash before haircuts and buffers available
    int256 localPrimeAvailable;
    // Amount of net collateral currency asset cash before haircuts and buffers available
    int256 collateralAssetAvailable;
    // Haircut value of nToken holdings denominated in asset cash, will be local or collateral nTokens based
    // on liquidation type
    int256 nTokenHaircutPrimeValue;
    // nToken parameters for calculating liquidation amount
    bytes6 nTokenParameters;
    // ETH exchange rate from local currency to ETH
    ETHRate localETHRate;
    // ETH exchange rate from collateral currency to ETH
    ETHRate collateralETHRate;
    // Asset rate for the local currency, used in cross currency calculations to calculate local asset cash required
    PrimeRate localPrimeRate;
    // Used during currency liquidations if the account has liquidity tokens
    CashGroupParameters collateralCashGroup;
    // Used during currency liquidations if it is only a calculation, defaults to false
    bool isCalculation;
}

/// @notice Internal asset array portfolio state
struct PortfolioState {
    // Array of currently stored assets
    PortfolioAsset[] storedAssets;
    // Array of new assets to add
    PortfolioAsset[] newAssets;
    uint256 lastNewAssetIndex;
    // Holds the length of stored assets after accounting for deleted assets
    uint256 storedAssetLength;
}

/// @notice In memory ETH exchange rate used during free collateral calculation.
struct ETHRate {
    // The decimals (i.e. 10^rateDecimalPlaces) of the exchange rate, defined by the rate oracle
    int256 rateDecimals;
    // The exchange rate from base to ETH (if rate invert is required it is already done)
    int256 rate;
    // Amount of buffer as a multiple with a basis of 100 applied to negative balances.
    int256 buffer;
    // Amount of haircut as a multiple with a basis of 100 applied to positive balances
    int256 haircut;
    // Liquidation discount as a multiple with a basis of 100 applied to the exchange rate
    // as an incentive given to liquidators.
    int256 liquidationDiscount;
}

/// @notice Internal object used to handle balance state during a transaction
struct BalanceState {
    uint16 currencyId;
    // Cash balance stored in balance state at the beginning of the transaction
    int256 storedCashBalance;
    // nToken balance stored at the beginning of the transaction
    int256 storedNTokenBalance;
    // The net cash change as a result of asset settlement or trading
    int256 netCashChange;
    // Amount of prime cash to redeem and withdraw from the system
    int256 primeCashWithdraw;
    // Net token transfers into or out of the account
    int256 netNTokenTransfer;
    // Net token supply change from minting or redeeming
    int256 netNTokenSupplyChange;
    // The last time incentives were claimed for this currency
    uint256 lastClaimTime;
    // Accumulator for incentives that the account no longer has a claim over
    uint256 accountIncentiveDebt;
    // Prime rate for converting prime cash balances
    PrimeRate primeRate;
}

/// @dev Asset rate used to convert between underlying cash and asset cash
struct Deprecated_AssetRateParameters {
    // Address of the asset rate oracle
    AssetRateAdapter rateOracle;
    // The exchange rate from base to quote (if invert is required it is already done)
    int256 rate;
    // The decimals of the underlying, the rate converts to the underlying decimals
    int256 underlyingDecimals;
}

/// @dev Cash group when loaded into memory
struct CashGroupParameters {
    uint16 currencyId;
    uint256 maxMarketIndex;
    PrimeRate primeRate;
    bytes32 data;
}

/// @dev A portfolio asset when loaded in memory
struct PortfolioAsset {
    // Asset currency id
    uint16 currencyId;
    uint256 maturity;
    // Asset type, fCash or liquidity token.
    uint256 assetType;
    // fCash amount or liquidity token amount
    int256 notional;
    // Used for managing portfolio asset state
    uint256 storageSlot;
    // The state of the asset for when it is written to storage
    AssetStorageState storageState;
}

/// @dev Market object as represented in memory
struct MarketParameters {
    bytes32 storageSlot;
    uint256 maturity;
    // Total amount of fCash available for purchase in the market.
    int256 totalfCash;
    // Total amount of cash available for purchase in the market.
    int256 totalPrimeCash;
    // Total amount of liquidity tokens (representing a claim on liquidity) in the market.
    int256 totalLiquidity;
    // This is the previous annualized interest rate in RATE_PRECISION that the market traded
    // at. This is used to calculate the rate anchor to smooth interest rates over time.
    uint256 lastImpliedRate;
    // Time lagged version of lastImpliedRate, used to value fCash assets at market rates while
    // remaining resistent to flash loan attacks.
    uint256 oracleRate;
    // This is the timestamp of the previous trade
    uint256 previousTradeTime;
}

/****** Storage objects ******/

/// @dev Token object in storage:
///  20 bytes for token address
///  1 byte for hasTransferFee
///  1 byte for tokenType
///  1 byte for tokenDecimals
///  9 bytes for maxCollateralBalance (may not always be set)
struct TokenStorage {
    // Address of the token
    address tokenAddress;
    // Transfer fees will change token deposit behavior
    bool hasTransferFee;
    TokenType tokenType;
    uint8 decimalPlaces;
    uint72 deprecated_maxCollateralBalance;
}

/// @dev Exchange rate object as it is represented in storage, total storage is 25 bytes.
struct ETHRateStorage {
    // Address of the rate oracle
    AggregatorV2V3Interface rateOracle;
    // The decimal places of precision that the rate oracle uses
    uint8 rateDecimalPlaces;
    // True of the exchange rate must be inverted
    bool mustInvert;
    // NOTE: both of these governance values are set with BUFFER_DECIMALS precision
    // Amount of buffer to apply to the exchange rate for negative balances.
    uint8 buffer;
    // Amount of haircut to apply to the exchange rate for positive balances
    uint8 haircut;
    // Liquidation discount in percentage point terms, 106 means a 6% discount
    uint8 liquidationDiscount;
}

/// @dev Asset rate oracle object as it is represented in storage, total storage is 21 bytes.
struct AssetRateStorage {
    // Address of the rate oracle
    AssetRateAdapter rateOracle;
    // The decimal places of the underlying asset
    uint8 underlyingDecimalPlaces;
}

/// @dev Governance parameters for a cash group, total storage is 9 bytes + 7 bytes for liquidity token haircuts
/// and 7 bytes for rate scalars, total of 23 bytes. Note that this is stored packed in the storage slot so there
/// are no indexes stored for liquidityTokenHaircuts or rateScalars, maxMarketIndex is used instead to determine the
/// length.
struct CashGroupSettings {
    // Index of the AMMs on chain that will be made available. Idiosyncratic fCash
    // that is dated less than the longest AMM will be tradable.
    uint8 maxMarketIndex;
    // Time window in 5 minute increments that the rate oracle will be averaged over
    uint8 rateOracleTimeWindow5Min;
    // Absolute maximum discount factor as a discount from 1e9, specified in five basis points
    // subtracted from 1e9
    uint8 maxDiscountFactor5BPS;
    // Share of the fees given to the protocol, denominated in percentage
    uint8 reserveFeeShare;
    // Debt buffer specified in 5 BPS increments
    uint8 debtBuffer25BPS;
    // fCash haircut specified in 5 BPS increments
    uint8 fCashHaircut25BPS;
    // Minimum oracle interest rates for fCash per market, specified in 25 bps increments
    uint8 minOracleRate25BPS;
    // If an account has fCash that is being liquidated, this is the discount that the liquidator can purchase it for
    uint8 liquidationfCashHaircut25BPS;
    // If an account has fCash that is being liquidated, this is the discount that the liquidator can purchase it for
    uint8 liquidationDebtBuffer25BPS;
    // Max oracle rate specified in 25bps increments as a discount from the max rate in the market.
    uint8 maxOracleRate25BPS;
}

/// @dev Holds account level context information used to determine settlement and
/// free collateral actions. Total storage is 28 bytes
struct AccountContext {
    // Used to check when settlement must be triggered on an account
    uint40 nextSettleTime;
    // For lenders that never incur debt, we use this flag to skip the free collateral check.
    bytes1 hasDebt;
    // Length of the account's asset array
    uint8 assetArrayLength;
    // If this account has bitmaps set, this is the corresponding currency id
    uint16 bitmapCurrencyId;
    // 9 total active currencies possible (2 bytes each)
    bytes18 activeCurrencies;
    // If this is set to true, the account can borrow variable prime cash and incur
    // negative cash balances inside BatchAction. This does not impact the settlement
    // of negative fCash to prime cash which will happen regardless of this setting. This
    // exists here mainly as a safety setting to ensure that accounts do not accidentally
    // incur negative cash balances.
    bool allowPrimeBorrow;
}

/// @dev Holds nToken context information mapped via the nToken address, total storage is
/// 16 bytes
struct nTokenContext {
    // Currency id that the nToken represents
    uint16 currencyId;
    // Annual incentive emission rate denominated in WHOLE TOKENS (multiply by
    // INTERNAL_TOKEN_PRECISION to get the actual rate)
    uint32 incentiveAnnualEmissionRate;
    // The last block time at utc0 that the nToken was initialized at, zero if it
    // has never been initialized
    uint32 lastInitializedTime;
    // Length of the asset array, refers to the number of liquidity tokens an nToken
    // currently holds
    uint8 assetArrayLength;
    // Each byte is a specific nToken parameter
    bytes6 nTokenParameters;
    // Reserved bytes for future usage
    bytes14 _unused;
    // Set to true if a secondary rewarder is set
    bool hasSecondaryRewarder;
}

/// @dev Holds account balance information, total storage 32 bytes
struct BalanceStorage {
    // Number of nTokens held by the account
    uint80 nTokenBalance;
    // Last time the account claimed their nTokens
    uint32 lastClaimTime;
    // Incentives that the account no longer has a claim over
    uint56 accountIncentiveDebt;
    // Cash balance of the account
    int88 cashBalance;
}

/// @dev Holds information about a settlement rate, total storage 25 bytes
struct SettlementRateStorage {
    uint40 blockTime;
    uint128 settlementRate;
    uint8 underlyingDecimalPlaces;
}

/// @dev Holds information about a market, total storage is 42 bytes so this spans
/// two storage words
struct MarketStorage {
    // Total fCash in the market
    uint80 totalfCash;
    // Total asset cash in the market
    uint80 totalPrimeCash;
    // Last annualized interest rate the market traded at
    uint32 lastImpliedRate;
    // Last recorded oracle rate for the market
    uint32 oracleRate;
    // Last time a trade was made
    uint32 previousTradeTime;
    // This is stored in slot + 1
    uint80 totalLiquidity;
}

struct InterestRateParameters {
    // First kink for the utilization rate in RATE_PRECISION
    uint256 kinkUtilization1;
    // Second kink for the utilization rate in RATE_PRECISION
    uint256 kinkUtilization2;
    // First kink interest rate in RATE_PRECISION
    uint256 kinkRate1;
    // Second kink interest rate in RATE_PRECISION
    uint256 kinkRate2;
    // Max interest rate in RATE_PRECISION
    uint256 maxRate;
    // Minimum fee charged in RATE_PRECISION
    uint256 minFeeRate;
    // Maximum fee charged in RATE_PRECISION
    uint256 maxFeeRate;
    // Percentage of the interest rate that will be applied as a fee
    uint256 feeRatePercent;
}

// Specific interest rate curve settings for each market
struct InterestRateCurveSettings {
    // First kink for the utilization rate, specified as a percentage
    // between 1-100
    uint8 kinkUtilization1;
    // Second kink for the utilization rate, specified as a percentage
    // between 1-100
    uint8 kinkUtilization2;
    // Interest rate at the first kink, set as 1/256 units from the kink
    // rate max
    uint8 kinkRate1;
    // Interest rate at the second kink, set as 1/256 units from the kink
    // rate max
    uint8 kinkRate2;
    // Max interest rate, set in units in 25bps increments less than or equal to 150
    // and 150bps increments from 151 to 255.
    uint8 maxRateUnits;
    // Minimum fee charged in basis points
    uint8 minFeeRate5BPS;
    // Maximum fee charged in basis points
    uint8 maxFeeRate25BPS;
    // Percentage of the interest rate that will be applied as a fee
    uint8 feeRatePercent;
}

struct ifCashStorage {
    // Notional amount of fCash at the slot, limited to int128 to allow for
    // future expansion
    int128 notional;
}

/// @dev A single portfolio asset in storage, total storage of 19 bytes
struct PortfolioAssetStorage {
    // Currency Id for the asset
    uint16 currencyId;
    // Maturity of the asset
    uint40 maturity;
    // Asset type (fCash or Liquidity Token marker)
    uint8 assetType;
    // Notional
    int88 notional;
}

/// @dev nToken total supply factors for the nToken, includes factors related
/// to claiming incentives, total storage 32 bytes. This is the deprecated version
struct nTokenTotalSupplyStorage_deprecated {
    // Total supply of the nToken
    uint96 totalSupply;
    // Integral of the total supply used for calculating the average total supply
    uint128 integralTotalSupply;
    // Last timestamp the supply value changed, used for calculating the integralTotalSupply
    uint32 lastSupplyChangeTime;
}

/// @dev nToken total supply factors for the nToken, includes factors related
/// to claiming incentives, total storage 32 bytes.
struct nTokenTotalSupplyStorage {
    // Total supply of the nToken
    uint96 totalSupply;
    // How many NOTE incentives should be issued per nToken in 1e18 precision
    uint128 accumulatedNOTEPerNToken;
    // Last timestamp when the accumulation happened
    uint32 lastAccumulatedTime;
}

/// @dev Used in view methods to return account balances in a developer friendly manner
struct AccountBalance {
    uint16 currencyId;
    int256 cashBalance;
    int256 nTokenBalance;
    uint256 lastClaimTime;
    uint256 accountIncentiveDebt;
}

struct VaultConfigParams {
    uint16 flags;
    uint16 borrowCurrencyId;
    uint256 minAccountBorrowSize;
    uint16 minCollateralRatioBPS;
    uint8 feeRate5BPS;
    uint8 liquidationRate;
    uint8 reserveFeeShare;
    uint8 maxBorrowMarketIndex;
    uint16 maxDeleverageCollateralRatioBPS;
    uint16[2] secondaryBorrowCurrencies;
    uint16 maxRequiredAccountCollateralRatioBPS;
    uint256[2] minAccountSecondaryBorrow;
    uint8 excessCashLiquidationBonus;
}

struct VaultConfigStorage {
    // Vault Flags (documented in VaultConfiguration.sol)
    uint16 flags;
    // Primary currency the vault borrows in
    uint16 borrowCurrencyId;
    // Specified in whole tokens in 1e8 precision, allows a 4.2 billion min borrow size
    uint32 minAccountBorrowSize;
    // Minimum collateral ratio for a vault specified in basis points, valid values are greater than 10_000
    // where the largest minimum collateral ratio is 65_536 which is much higher than anything reasonable.
    uint16 minCollateralRatioBPS;
    // Allows up to a 12.75% annualized fee
    uint8 feeRate5BPS;
    // A percentage that represents the share of the cash raised that will go to the liquidator
    uint8 liquidationRate;
    // A percentage of the fee given to the protocol
    uint8 reserveFeeShare;
    // Maximum market index where a vault can borrow from
    uint8 maxBorrowMarketIndex;
    // Maximum collateral ratio that a liquidator can push a an account to during deleveraging
    uint16 maxDeleverageCollateralRatioBPS;
    // An optional list of secondary borrow currencies
    uint16[2] secondaryBorrowCurrencies;
    // Required collateral ratio for accounts to stay inside a vault, prevents accounts
    // from "free riding" on vaults. Enforced on entry and exit, not on deleverage.
    uint16 maxRequiredAccountCollateralRatioBPS;
    // Specified in whole tokens in 1e8 precision, allows a 4.2 billion min borrow size
    uint32[2] minAccountSecondaryBorrow;
    // Specified as a percent discount off the exchange rate of the excess cash that will be paid to
    // the liquidator during liquidateExcessVaultCash
    uint8 excessCashLiquidationBonus;
    // 8 bytes left
}

struct VaultBorrowCapacityStorage {
    // Total fCash across all maturities that caps the borrow capacity
    uint80 maxBorrowCapacity;
    // Total fCash debt across all maturities
    uint80 totalfCashDebt;
}

struct VaultAccountSecondaryDebtShareStorage {
    // Maturity for the account's secondary borrows. This is stored separately from
    // the vault account maturity to ensure that we have access to the proper state
    // during a roll borrow position. It should never be allowed to deviate from the
    // vaultAccount.maturity value (unless it is cleared to zero).
    uint40 maturity;
    // Account debt for the first secondary currency in either fCash or pCash denomination
    uint80 accountDebtOne;
    // Account debt for the second secondary currency in either fCash or pCash denomination
    uint80 accountDebtTwo;
}

struct VaultConfig {
    address vault;
    uint16 flags;
    uint16 borrowCurrencyId;
    int256 minAccountBorrowSize;
    int256 feeRate;
    int256 minCollateralRatio;
    int256 liquidationRate;
    int256 reserveFeeShare;
    uint256 maxBorrowMarketIndex;
    int256 maxDeleverageCollateralRatio;
    uint16[2] secondaryBorrowCurrencies;
    PrimeRate primeRate;
    int256 maxRequiredAccountCollateralRatio;
    int256[2] minAccountSecondaryBorrow;
    int256 excessCashLiquidationBonus;
}

/// @notice Represents a Vault's current borrow and collateral state
struct VaultStateStorage {
    // This represents the total amount of borrowing in the vault for the current
    // vault term. If the vault state is the prime cash maturity, this is stored in
    // prime cash debt denomination, if fCash then it is stored in internal underlying.
    uint80 totalDebt;
    // The total amount of prime cash in the pool held as a result of emergency settlement
    uint80 deprecated_totalPrimeCash;
    // Total vault shares in this maturity
    uint80 totalVaultShares;
    // Set to true if a vault's debt position has been migrated to the prime cash vault
    bool isSettled;
    // NOTE: 8 bits left
    // ----- This breaks into a new storage slot -------    
    // The total amount of strategy tokens held in the pool
    uint80 deprecated_totalStrategyTokens;
    // Valuation of a strategy token at settlement
    int80 deprecated_settlementStrategyTokenValue;
    // NOTE: 96 bits left
}

/// @notice Represents the remaining assets in a vault post settlement
struct Deprecated_VaultSettledAssetsStorage {
    // Remaining strategy tokens that have not been withdrawn
    uint80 remainingStrategyTokens;
    // Remaining asset cash that has not been withdrawn
    int80 remainingPrimeCash;
}

struct VaultState {
    uint256 maturity;
    // Total debt is always denominated in underlying on the stack
    int256 totalDebtUnderlying;
    uint256 totalVaultShares;
    bool isSettled;
}

/// @notice Represents an account's position within an individual vault
struct VaultAccountStorage {
    // Total amount of debt for the account in the primary borrowed currency.
    // If the account is borrowing prime cash, this is stored in prime cash debt
    // denomination, if fCash then it is stored in internal underlying.
    uint80 accountDebt;
    // Vault shares that the account holds
    uint80 vaultShares;
    // Maturity when the vault shares and fCash will mature
    uint40 maturity;
    // Last time when a vault was entered or exited, used to ensure that vault accounts do not
    // flash enter/exit. While there is no specified attack vector here, we can use it to prevent
    // an entire class of attacks from happening without reducing UX.
    // NOTE: in the original version this value was set to the block.number, however, in this
    // version it is being changed to time based. On ETH mainnet block heights are much smaller
    // than block times, accounts that migrate from lastEntryBlockHeight => lastUpdateBlockTime
    // will not see any issues with entering / exiting the protocol.
    uint32 lastUpdateBlockTime;
    // ----------------  Second Storage Slot ----------------------
    // Cash balances held by the vault account as a result of lending at zero interest or due
    // to deleveraging (liquidation). In the previous version of leveraged vaults, accounts would
    // simply lend at zero interest which was not a problem. However, with vaults being able to
    // discount fCash to present value, lending at zero percent interest may have an adverse effect
    // on the account's collateral position (i.e. lending at zero puts them further into danger).
    // Holding cash against debt will eliminate that risk, making vault liquidation more similar to
    // regular Notional liquidation.
    uint80 primaryCash;
    uint80 secondaryCashOne;
    uint80 secondaryCashTwo;
}

struct VaultAccount {
    // On the stack, account debts are always in underlying
    int256 accountDebtUnderlying;
    uint256 maturity;
    uint256 vaultShares;
    address account;
    // This cash balance is used just within a transaction to track deposits
    // and withdraws for an account. Must be zeroed by the time we store the account
    int256 tempCashBalance;
    uint256 lastUpdateBlockTime;
}

// Used to hold vault account liquidation factors in memory
struct VaultAccountHealthFactors {
    // Account's calculated collateral ratio
    int256 collateralRatio;
    // Total outstanding debt across all borrowed currencies in primary
    int256 totalDebtOutstandingInPrimary;
    // Total value of vault shares in underlying denomination
    int256 vaultShareValueUnderlying;
    // Debt outstanding in local currency denomination after present value and
    // account cash held netting applied. Can be positive if the account holds cash
    // in excess of debt.
    int256[3] netDebtOutstanding;
}

// PrimeCashInterestRateParameters take up 16 bytes, this takes up 32 bytes so we
// can expand another 16 bytes to increase the storage slots a bit....
struct PrimeCashFactorsStorage {
    // Storage slot 1 [Prime Supply Factors, 248 bytes]
    uint40 lastAccrueTime;
    uint88 totalPrimeSupply;
    uint88 lastTotalUnderlyingValue;
    // Overflows at 429% interest using RATE_PRECISION
    uint32 oracleSupplyRate;
    bool allowDebt;

    // Storage slot 2 [Prime Debt Factors, 256 bytes]
    uint88 totalPrimeDebt;
    // Each one of these values below is stored as a FloatingPoint32 value which
    // gives us approx 7 digits of precision for each value. Because these are used
    // to maintain supply and borrow caps, they are not required to be exact.
    uint32 maxUnderlyingSupply;
    // The maximum utilization that prime debt is allowed to reach by users borrowing prime
    // debt via the markets directly. This cap is not applied to liquidations and settlement.
    uint8 maxPrimeDebtUtilization;
    uint120 _reserved;
    // Reserving the next 128 bytes for future use in case we decide to implement debt
    // caps on a currency. In that case, we will need to track the total fcash overall
    // and subtract the total debt held in vaults.
    // uint32 maxUnderlyingDebt;
    // uint32 totalfCashDebtOverall;
    // uint32 totalfCashDebtInVaults;
    // uint32 totalPrimeDebtInVaults;
    // 8 bytes left
    
    // Storage slot 3 [Prime Scalars, 240 bytes]
    // Scalars are stored in 18 decimal precision (i.e. double rate precision) and uint80
    // maxes out at approx 1,210,000e18
    // ln(1,210,000) = rate * years = 14
    // Approx 46 years at 30% interest
    // Approx 233 years at 6% interest
    uint80 underlyingScalar;
    uint80 supplyScalar;
    uint80 debtScalar;
    // The time window in 5 min increments that the rate oracle will be averaged over
    uint8 rateOracleTimeWindow5Min;
    // 8 bytes left
}

struct PrimeCashFactors {
    uint256 lastAccrueTime;
    uint256 totalPrimeSupply;
    uint256 totalPrimeDebt;
    uint256 oracleSupplyRate;
    uint256 lastTotalUnderlyingValue;
    uint256 underlyingScalar;
    uint256 supplyScalar;
    uint256 debtScalar;
    uint256 rateOracleTimeWindow;
}

struct PrimeRate {
    int256 supplyFactor;
    int256 debtFactor;
    uint256 oracleSupplyRate;
}

struct PrimeSettlementRateStorage {
    uint80 supplyScalar;
    uint80 debtScalar;
    uint80 underlyingScalar;
    bool isSet;
}

struct PrimeCashHoldingsOracle {
   IPrimeCashHoldingsOracle oracle; 
}

// Per currency rebalancing context
struct RebalancingContextStorage {
    // Holds the previous supply factor to calculate the oracle money market rate
    uint128 previousSupplyFactorAtRebalance;
    // Rebalancing has a cool down period that sets the time averaging of the oracle money market rate
    uint40 rebalancingCooldownInSeconds;
    uint40 lastRebalanceTimestampInSeconds;
    // 48 bytes left
}

struct TotalfCashDebtStorage {
    uint80 totalfCashDebt;
    // These two variables are used to track fCash lend at zero
    // edge conditions for leveraged vaults.
    uint80 fCashDebtHeldInSettlementReserve;
    uint80 primeCashHeldInSettlementReserve;
}

struct RebalancingTargetData {
    uint8 targetUtilization;
    uint16 externalWithdrawThreshold;
}

File 6 of 29 : GenericToken.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity =0.7.6;

import {Deployments} from "../../../global/Deployments.sol";
import {IEIP20NonStandard} from "../../../../interfaces/IEIP20NonStandard.sol";
import {SafeUint256} from "../../../math/SafeUint256.sol";

library GenericToken {
    using SafeUint256 for uint256;

    event LowLevelCallFailed(address indexed target, uint256 msgValue, bytes callData, string revertMessage);

    function transferNativeTokenOut(
        address account,
        uint256 amount,
        bool withdrawWrapped
    ) internal {
        // Native token withdraws are processed using .transfer() which is may not work
        // for certain contracts that do not implement receive() with minimal gas requirements.
        // Prior to the prime cash upgrade, these contracts could withdraw cETH, however, post
        // upgrade they no longer have this option. For these contracts, wrap the Native token
        // (i.e. WETH) and transfer that as an ERC20 instead.
        if (withdrawWrapped) {
            Deployments.WETH.deposit{value: amount}();
            safeTransferOut(address(Deployments.WETH), account, amount);
        } else {
            // TODO: consider using .call with a manual amount of gas forwarding
            payable(account).transfer(amount);
        }
    }

    function safeTransferOut(
        address token,
        address account,
        uint256 amount
    ) internal {
        IEIP20NonStandard(token).transfer(account, amount);
        checkReturnCode();
    }

    function safeTransferIn(
        address token,
        address account,
        uint256 amount
    ) internal returns (uint256) {
        uint256 startingBalance = IEIP20NonStandard(token).balanceOf(address(this));

        IEIP20NonStandard(token).transferFrom(account, address(this), amount);
        checkReturnCode();

        uint256 endingBalance = IEIP20NonStandard(token).balanceOf(address(this));

        return endingBalance.sub(startingBalance);
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 amount
    ) internal {
        IEIP20NonStandard(token).transferFrom(from, to, amount);
        checkReturnCode();
    }

    function executeLowLevelCall(
        address target,
        uint256 msgValue,
        bytes memory callData
    ) internal  {
        (bool status, bytes memory returnData) = target.call{value: msgValue}(callData);
        require(status, checkRevertMessage(returnData));
    }

    function checkRevertMessage(bytes memory returnData) internal pure returns (string memory) {
        // If the _res length is less than 68, then the transaction failed silently (without a revert message)
        if (returnData.length < 68) return "Silent Revert";

        assembly {
            // Slice the sighash.
            returnData := add(returnData, 0x04)
        }
        return abi.decode(returnData, (string)); // All that remains is the revert string
    }

    function checkReturnCode() internal pure {
        bool success;
        uint256[1] memory result;
        assembly {
            switch returndatasize()
                case 0 {
                    // This is a non-standard ERC-20
                    success := 1 // set success to true
                }
                case 32 {
                    // This is a compliant ERC-20
                    returndatacopy(result, 0, 32)
                    success := mload(result) // Set `success = returndata` of external call
                }
                default {
                    // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }

        require(success, "ERC20");
    }

}

File 7 of 29 : Bitmap.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity =0.7.6;
pragma abicoder v2;

import {Constants} from "../global/Constants.sol";

/// @notice Helper methods for bitmaps, they are big-endian and 1-indexed.
library Bitmap {

    /// @notice Set a bit on or off in a bitmap, index is 1-indexed
    function setBit(
        bytes32 bitmap,
        uint256 index,
        bool setOn
    ) internal pure returns (bytes32) {
        require(index >= 1 && index <= 256); // dev: set bit index bounds

        if (setOn) {
            return bitmap | (Constants.MSB >> (index - 1));
        } else {
            return bitmap & ~(Constants.MSB >> (index - 1));
        }
    }

    /// @notice Check if a bit is set
    function isBitSet(bytes32 bitmap, uint256 index) internal pure returns (bool) {
        require(index >= 1 && index <= 256); // dev: set bit index bounds
        return ((bitmap << (index - 1)) & Constants.MSB) == Constants.MSB;
    }

    /// @notice Count the total bits set
    function totalBitsSet(bytes32 bitmap) internal pure returns (uint256) {
        uint256 x = uint256(bitmap);
        x = (x & 0x5555555555555555555555555555555555555555555555555555555555555555) + (x >> 1 & 0x5555555555555555555555555555555555555555555555555555555555555555);
        x = (x & 0x3333333333333333333333333333333333333333333333333333333333333333) + (x >> 2 & 0x3333333333333333333333333333333333333333333333333333333333333333);
        x = (x & 0x0707070707070707070707070707070707070707070707070707070707070707) + (x >> 4);
        x = (x & 0x000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F) + (x >> 8 & 0x000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F);
        x = x + (x >> 16);
        x = x + (x >> 32);
        x = x  + (x >> 64);
        return (x & 0xFF) + (x >> 128 & 0xFF);
    }

    // Does a binary search over x to get the position of the most significant bit
    function getMSB(uint256 x) internal pure returns (uint256 msb) {
        // If x == 0 then there is no MSB and this method will return zero. That would
        // be the same as the return value when x == 1 (MSB is zero indexed), so instead
        // we have this require here to ensure that the values don't get mixed up.
        require(x != 0); // dev: get msb zero value
        if (x >= 0x100000000000000000000000000000000) {
            x >>= 128;
            msb += 128;
        }
        if (x >= 0x10000000000000000) {
            x >>= 64;
            msb += 64;
        }
        if (x >= 0x100000000) {
            x >>= 32;
            msb += 32;
        }
        if (x >= 0x10000) {
            x >>= 16;
            msb += 16;
        }
        if (x >= 0x100) {
            x >>= 8;
            msb += 8;
        }
        if (x >= 0x10) {
            x >>= 4;
            msb += 4;
        }
        if (x >= 0x4) {
            x >>= 2;
            msb += 2;
        }
        if (x >= 0x2) msb += 1; // No need to shift xc anymore
    }

    /// @dev getMSB returns a zero indexed bit number where zero is the first bit counting
    /// from the right (little endian). Asset Bitmaps are counted from the left (big endian)
    /// and one indexed.
    function getNextBitNum(bytes32 bitmap) internal pure returns (uint256 bitNum) {
        // Short circuit the search if bitmap is all zeros
        if (bitmap == 0x00) return 0;

        return 255 - getMSB(uint256(bitmap)) + 1;
    }
}

File 8 of 29 : FloatingPoint.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity =0.7.6;

import {Bitmap} from "./Bitmap.sol";
import {SafeInt256} from "./SafeInt256.sol";
import {SafeUint256} from "./SafeUint256.sol";

/**
 * Packs an uint value into a "floating point" storage slot. Used for storing
 * lastClaimIntegralSupply values in balance storage. For these values, we don't need
 * to maintain exact precision but we don't want to be limited by storage size overflows.
 *
 * A floating point value is defined by the 48 most significant bits and an 8 bit number
 * of bit shifts required to restore its precision. The unpacked value will always be less
 * than the packed value with a maximum absolute loss of precision of (2 ** bitShift) - 1.
 */
library FloatingPoint {
    using SafeInt256 for int256;
    using SafeUint256 for uint256;

    function packTo56Bits(uint256 value) internal pure returns (uint56) {
        uint256 bitShift;
        // If the value is over the uint48 max value then we will shift it down
        // given the index of the most significant bit. We store this bit shift 
        // in the least significant byte of the 56 bit slot available.
        if (value > type(uint48).max) bitShift = (Bitmap.getMSB(value) - 47);

        uint256 shiftedValue = value >> bitShift;
        return uint56((shiftedValue << 8) | bitShift);
    }

    function packTo32Bits(uint256 value) internal pure returns (uint32) {
        uint256 bitShift;
        // If the value is over the uint24 max value then we will shift it down
        // given the index of the most significant bit. We store this bit shift 
        // in the least significant byte of the 32 bit slot available.
        if (value > type(uint24).max) bitShift = (Bitmap.getMSB(value) - 23);

        uint256 shiftedValue = value >> bitShift;
        return uint32((shiftedValue << 8) | bitShift);
    }

    function unpackFromBits(uint256 value) internal pure returns (uint256) {
        // The least significant 8 bits will be the amount to bit shift
        uint256 bitShift = uint256(uint8(value));
        return ((value >> 8) << bitShift);
    }
}

File 9 of 29 : SafeInt256.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity =0.7.6;

import {Constants} from "../global/Constants.sol";

library SafeInt256 {
    int256 private constant _INT256_MIN = type(int256).min;

    /// @dev Returns the multiplication of two signed integers, reverting on
    /// overflow.

    /// Counterpart to Solidity's `*` operator.

    /// Requirements:

    /// - Multiplication cannot overflow.

    function mul(int256 a, int256 b) internal pure returns (int256 c) {
        c = a * b;
        if (a == -1) require (b == 0 || c / b == a);
        else require (a == 0 || c / a == b);
    }

    /// @dev Returns the integer division of two signed integers. Reverts on
    /// division by zero. The result is rounded towards zero.

    /// Counterpart to Solidity's `/` operator. Note: this function uses a
    /// `revert` opcode (which leaves remaining gas untouched) while Solidity
    /// uses an invalid opcode to revert (consuming all remaining gas).

    /// Requirements:

    /// - The divisor cannot be zero.

    function div(int256 a, int256 b) internal pure returns (int256 c) {
        require(!(b == -1 && a == _INT256_MIN)); // dev: int256 div overflow
        // NOTE: solidity will automatically revert on divide by zero
        c = a / b;
    }

    function sub(int256 x, int256 y) internal pure returns (int256 z) {
        //  taken from uniswap v3
        require((z = x - y) <= x == (y >= 0));
    }

    function add(int256 x, int256 y) internal pure returns (int256 z) {
        require((z = x + y) >= x == (y >= 0));
    }

    function neg(int256 x) internal pure returns (int256 y) {
        return mul(-1, x);
    }

    function abs(int256 x) internal pure returns (int256) {
        if (x < 0) return neg(x);
        else return x;
    }

    function subNoNeg(int256 x, int256 y) internal pure returns (int256 z) {
        z = sub(x, y);
        require(z >= 0); // dev: int256 sub to negative

        return z;
    }

    /// @dev Calculates x * RATE_PRECISION / y while checking overflows
    function divInRatePrecision(int256 x, int256 y) internal pure returns (int256) {
        return div(mul(x, Constants.RATE_PRECISION), y);
    }

    /// @dev Calculates x * y / RATE_PRECISION while checking overflows
    function mulInRatePrecision(int256 x, int256 y) internal pure returns (int256) {
        return div(mul(x, y), Constants.RATE_PRECISION);
    }

    function toUint(int256 x) internal pure returns (uint256) {
        require(x >= 0);
        return uint256(x);
    }

    function toInt(uint256 x) internal pure returns (int256) {
        require (x <= uint256(type(int256).max)); // dev: toInt overflow
        return int256(x);
    }

    function toInt80(int256 x) internal pure returns (int80) {
        require (int256(type(int80).min) <= x && x <= int256(type(int80).max)); // dev: toInt overflow
        return int80(x);
    }

    function toInt88(int256 x) internal pure returns (int88) {
        require (int256(type(int88).min) <= x && x <= int256(type(int88).max)); // dev: toInt overflow
        return int88(x);
    }

    function toInt128(int256 x) internal pure returns (int128) {
        require (int256(type(int128).min) <= x && x <= int256(type(int128).max)); // dev: toInt overflow
        return int128(x);
    }

    function max(int256 x, int256 y) internal pure returns (int256) {
        return x > y ? x : y;
    }

    function min(int256 x, int256 y) internal pure returns (int256) {
        return x < y ? x : y;
    }

    /// @notice Returns the net change in negative signed values, used for
    /// determining the (positive) amount of debt change
    function negChange(int256 start, int256 end) internal pure returns (int256) {
        // No change in these two scenarios
        if (start == end || (start >= 0 && end >= 0)) return 0;
        if (start <= 0 && 0 < end) {
            // Negative portion has been eliminated so the net change on the
            // negative side is start (i.e. a reduction in the negative balance)
            return start;
        } else if (end <= 0 && 0 < start) {
            // Entire negative portion has been created so the net change on the
            // negative side is -end (i.e. an increase in the negative balance)
            return neg(end);
        } else if (start <= 0 && end <= 0) {
            // There is some net change in the negative amounts.
            // If start < end then this is negative, debt has been reduced
            // If end < start then this is positive, debt has been increased
            return sub(start, end);
        }

        // Should never get to this point
        revert();
    }
}

File 10 of 29 : SafeUint256.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity =0.7.6;

import {Constants} from "../global/Constants.sol";

library SafeUint256 {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b);
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0);
        return a / b;
    }

    function max(uint256 x, uint256 y) internal pure returns (uint256) {
        return x > y ? x : y;
    }

    function min(uint256 x, uint256 y) internal pure returns (uint256) {
        return x < y ? x : y;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0);
        return a % b;
    }

    function divInRatePrecision(uint256 x, uint256 y) internal pure returns (uint256) {
        return div(mul(x, uint256(Constants.RATE_PRECISION)), y);
    }

    function mulInRatePrecision(uint256 x, uint256 y) internal pure returns (uint256) {
        return div(mul(x, y), uint256(Constants.RATE_PRECISION));
    }

    function divInScalarPrecision(uint256 x, uint256 y) internal pure returns (uint256) {
        return div(mul(x, Constants.SCALAR_PRECISION), y);
    }

    function mulInScalarPrecision(uint256 x, uint256 y) internal pure returns (uint256) {
        return div(mul(x, y), Constants.SCALAR_PRECISION);
    }

    function toUint8(uint256 x) internal pure returns (uint8) {
        require(x <= type(uint8).max);
        return uint8(x);
    }

    function toUint32(uint256 x) internal pure returns (uint32) {
        require(x <= type(uint32).max);
        return uint32(x);
    }

    function toUint40(uint256 x) internal pure returns (uint40) {
        require(x <= type(uint40).max);
        return uint40(x);
    }

    function toUint48(uint256 x) internal pure returns (uint48) {
        require(x <= type(uint48).max);
        return uint48(x);
    }

    function toUint56(uint256 x) internal pure returns (uint56) {
        require(x <= type(uint56).max);
        return uint56(x);
    }

    function toUint72(uint256 x) internal pure returns (uint72) {
        require(x <= type(uint72).max);
        return uint72(x);
    }
    
    function toUint80(uint256 x) internal pure returns (uint80) {
        require(x <= type(uint80).max);
        return uint80(x);
    }

    function toUint88(uint256 x) internal pure returns (uint88) {
        require(x <= type(uint88).max);
        return uint88(x);
    }

    function toUint104(uint256 x) internal pure returns (uint104) {
        require(x <= type(uint104).max);
        return uint104(x);
    }

    function toUint112(uint256 x) internal pure returns (uint112) {
        require(x <= type(uint112).max);
        return uint112(x);
    }

    function toUint128(uint256 x) internal pure returns (uint128) {
        require(x <= type(uint128).max);
        return uint128(x);
    }

    function toInt(uint256 x) internal pure returns (int256) {
        require (x <= uint256(type(int256).max)); // dev: toInt overflow
        return int256(x);
    }

}

File 11 of 29 : IBeacon.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.3.2 (proxy/beacon/IBeacon.sol)

pragma solidity >=0.7.6;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

interface IUpgradeableBeacon is IBeacon {
    function upgradeTo(address newImplementation) external;
}

File 12 of 29 : ILendingPool.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

struct LendingPoolStorage {
  ILendingPool lendingPool;
}

interface ILendingPool {

  /**
   * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
   * - E.g. User deposits 100 USDC and gets in return 100 aUSDC
   * @param asset The address of the underlying asset to deposit
   * @param amount The amount to be deposited
   * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
   *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
   *   is a different wallet
   * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   **/
  function deposit(
    address asset,
    uint256 amount,
    address onBehalfOf,
    uint16 referralCode
  ) external;

  /**
   * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
   * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
   * @param asset The address of the underlying asset to withdraw
   * @param amount The underlying amount to be withdrawn
   *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
   * @param to Address that will receive the underlying, same as msg.sender if the user
   *   wants to receive it on his own wallet, or a different address if the beneficiary is a
   *   different wallet
   * @return The final amount withdrawn
   **/
  function withdraw(
    address asset,
    uint256 amount,
    address to
  ) external returns (uint256);

  /**
   * @dev Returns the normalized income normalized income of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The reserve's normalized income
   */
  function getReserveNormalizedIncome(address asset) external view returns (uint256);

    /**
   * @dev Returns the state and configuration of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The state of the reserve
   **/
  function getReserveData(address asset) external view returns (ReserveData memory);

  struct ReserveData {
    ReserveConfigurationMap configuration;
    uint128 liquidityIndex;
    uint128 currentLiquidityRate;
    uint128 variableBorrowIndex;
    uint128 currentVariableBorrowRate;
    uint128 currentStableBorrowRate;
    uint40 lastUpdateTimestamp;
    uint16 id;
    address aTokenAddress;
    address stableDebtTokenAddress;
    address variableDebtTokenAddress;
    address interestRateStrategyAddress;
    uint128 accruedToTreasury;
    uint128 unbacked;
    uint128 isolationModeTotalDebt;
  }

  struct ReserveConfigurationMap {
    //bit 0-15: LTV
    //bit 16-31: Liq. threshold
    //bit 32-47: Liq. bonus
    //bit 48-55: Decimals
    //bit 56: Reserve is active
    //bit 57: reserve is frozen
    //bit 58: borrowing is enabled
    //bit 59: stable rate borrowing enabled
    //bit 60-63: reserved
    //bit 64-79: reserve factor
    uint256 data;
  }

  struct UserConfigurationMap {
    uint256 data;
  }

  enum InterestRateMode {NONE, STABLE, VARIABLE}
}

File 13 of 29 : AggregatorInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

interface AggregatorInterface {
  function latestAnswer() external view returns (int256);
  function latestTimestamp() external view returns (uint256);
  function latestRound() external view returns (uint256);
  function getAnswer(uint256 roundId) external view returns (int256);
  function getTimestamp(uint256 roundId) external view returns (uint256);

  event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
  event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}

File 14 of 29 : AggregatorV2V3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

import "./AggregatorInterface.sol";
import "./AggregatorV3Interface.sol";

interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
{
}

File 15 of 29 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;

interface AggregatorV3Interface {

  function decimals() external view returns (uint8);
  function description() external view returns (string memory);
  function version() external view returns (uint256);

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(uint80 _roundId)
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

}

File 16 of 29 : IEIP20NonStandard.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;

/**
 * @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 IEIP20NonStandard {

    /**
     * @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 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` does not return a value, in violation of the ERC-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @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
      */
    function approve(address spender, uint256 amount) external;

    /**
      * @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 remaining 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);
}

File 17 of 29 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    function decimals() external view returns (uint8);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 18 of 29 : AssetRateAdapter.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.0;

/// @notice Used as a wrapper for tokens that are interest bearing for an
/// underlying token. Follows the cToken interface, however, can be adapted
/// for other interest bearing tokens.
interface AssetRateAdapter {
    function token() external view returns (address);

    function decimals() external view returns (uint8);

    function description() external view returns (string memory);

    function version() external view returns (uint256);

    function underlying() external view returns (address);

    function getExchangeRateStateful() external returns (int256);

    function getExchangeRateView() external view returns (int256);

    function getAnnualizedSupplyRate() external view returns (uint256);
}

File 19 of 29 : IPrimeCashHoldingsOracle.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.0;
pragma abicoder v2;

struct DepositData {
    address[] targets;
    bytes[] callData;
    uint256[] msgValue;
    uint256 underlyingDepositAmount;
    address assetToken;
    uint8 rebasingTokenBalanceAdjustment;
}

struct RedeemData {
    address[] targets;
    bytes[] callData;
    uint256 expectedUnderlying;
    address assetToken;
    uint8 rebasingTokenBalanceAdjustment;
}

struct OracleData {
    address holding;
    uint256 externalUnderlyingAvailableForWithdraw;
    uint256 currentExternalUnderlyingLend;
    uint256 maxExternalDeposit;
}

interface IPrimeCashHoldingsOracle {
    /// @notice Returns a list of the various holdings for the prime cash
    /// currency
    function holdings() external view returns (address[] memory);

    /// @notice Returns the underlying token that all holdings can be redeemed
    /// for.
    function underlying() external view returns (address);

    /// @notice Returns the native decimal precision of the underlying token
    function decimals() external view returns (uint8);

    /// @notice Returns the total underlying held by the caller in all the
    /// listed holdings
    function getTotalUnderlyingValueStateful() external returns (
        uint256 nativePrecision,
        uint256 internalPrecision
    );

    function getTotalUnderlyingValueView() external view returns (
        uint256 nativePrecision,
        uint256 internalPrecision
    );

    /// @notice Returns calldata for how to withdraw an amount
    function getRedemptionCalldata(uint256 withdrawAmount) external view returns (
        RedeemData[] memory redeemData
    );

    function holdingValuesInUnderlying() external view returns (uint256[] memory);

    function getRedemptionCalldataForRebalancing(
        address[] calldata _holdings, 
        uint256[] calldata withdrawAmounts
    ) external view returns (
        RedeemData[] memory redeemData
    );

    function getDepositCalldataForRebalancing(
        address[] calldata _holdings,
        uint256[] calldata depositAmounts
    ) external view returns (
        DepositData[] memory depositData
    );

    function getOracleData() external view returns (OracleData memory);
}

File 20 of 29 : IRewarder.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;

interface IRewarder {
    event RewardTransfer(address indexed rewardToken, address indexed account, uint256 amount);
    event RewardEmissionUpdate(uint256 emissionRatePerYear, uint256 endTime);

    function NTOKEN_ADDRESS() external returns(address);

    function CURRENCY_ID() external returns(uint16);

    function detached() external returns(bool);

    function claimRewards(
        address account,
        uint16 currencyId,
        uint256 nTokenBalanceBefore,
        uint256 nTokenBalanceAfter,
        uint256 totalSupply
    ) external;

    function getAccountRewardClaim(address account, uint32 blockTime) external returns (uint256);

    function getAccountRewardClaim(address account, uint256 nTokenBalanceAtDetach, bytes32[] calldata proof)
        external
        returns (uint256);

    function claimRewardsDirect(address account, uint256 nTokenBalanceAtDetach, bytes32[] calldata proof) external;

    function accumulatedRewardPerNToken() external returns (uint128);

    function lastAccumulatedTime() external returns (uint32);

    function emissionRatePerYear() external returns (uint128);

    function detach() external;
}

File 21 of 29 : IVaultController.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import {
    VaultConfigParams,
    VaultConfigStorage,
    VaultConfig,
    VaultState,
    VaultAccount,
    VaultAccountHealthFactors,
    PrimeRate
} from "../../contracts/global/Types.sol";

interface IVaultAction {
    /// @notice Emitted when a new vault is listed or updated
    event VaultUpdated(address indexed vault, bool enabled, uint80 maxPrimaryBorrowCapacity);
    /// @notice Emitted when a vault's status is updated
    event VaultPauseStatus(address indexed vault, bool enabled);
    /// @notice Emitted when a vault's deleverage status is updated
    event VaultDeleverageStatus(address indexed vaultAddress, bool disableDeleverage);
    /// @notice Emitted when a secondary currency borrow capacity is updated
    event VaultUpdateSecondaryBorrowCapacity(address indexed vault, uint16 indexed currencyId, uint80 maxSecondaryBorrowCapacity);
    /// @notice Emitted when the borrow capacity on a vault changes
    event VaultBorrowCapacityChange(address indexed vault, uint16 indexed currencyId, uint256 totalUsedBorrowCapacity);

    /// @notice Emitted when a vault executes a secondary borrow
    event VaultSecondaryTransaction(
        address indexed vault,
        address indexed account,
        uint16 indexed currencyId,
        uint256 maturity,
        int256 netUnderlyingDebt,
        int256 netPrimeSupply
    );

    /** Vault Action Methods */

    /// @notice Governance only method to whitelist a particular vault
    function updateVault(
        address vaultAddress,
        VaultConfigParams memory vaultConfig,
        uint80 maxPrimaryBorrowCapacity
    ) external;

    /// @notice Governance only method to pause a particular vault
    function setVaultPauseStatus(
        address vaultAddress,
        bool enable
    ) external;

    function setVaultDeleverageStatus(
        address vaultAddress,
        bool disableDeleverage
    ) external;

    /// @notice Governance only method to set the borrow capacity
    function setMaxBorrowCapacity(
        address vaultAddress,
        uint80 maxVaultBorrowCapacity
    ) external;

    /// @notice Governance only method to update a vault's secondary borrow capacity
    function updateSecondaryBorrowCapacity(
        address vaultAddress,
        uint16 secondaryCurrencyId,
        uint80 maxBorrowCapacity
    ) external;

    function borrowSecondaryCurrencyToVault(
        address account,
        uint256 maturity,
        uint256[2] calldata underlyingToBorrow,
        uint32[2] calldata maxBorrowRate,
        uint32[2] calldata minRollLendRate
    ) external returns (int256[2] memory underlyingTokensTransferred);

    function repaySecondaryCurrencyFromVault(
        address account,
        uint256 maturity,
        uint256[2] calldata underlyingToRepay,
        uint32[2] calldata minLendRate
    ) external payable returns (int256[2] memory underlyingDepositExternal);

    function settleSecondaryBorrowForAccount(address vault, address account) external;
}

interface IVaultAccountAction {
    /**
     * @notice Borrows a specified amount of fCash in the vault's borrow currency and deposits it
     * all plus the depositAmountExternal into the vault to mint strategy tokens.
     *
     * @param account the address that will enter the vault
     * @param vault the vault to enter
     * @param depositAmountExternal some amount of additional collateral in the borrowed currency
     * to be transferred to vault
     * @param maturity the maturity to borrow at
     * @param fCash amount to borrow
     * @param maxBorrowRate maximum interest rate to borrow at
     * @param vaultData additional data to pass to the vault contract
     */
    function enterVault(
        address account,
        address vault,
        uint256 depositAmountExternal,
        uint256 maturity,
        uint256 fCash,
        uint32 maxBorrowRate,
        bytes calldata vaultData
    ) external payable returns (uint256 strategyTokensAdded);

    /**
     * @notice Re-enters the vault at a longer dated maturity. The account's existing borrow
     * position will be closed and a new borrow position at the specified maturity will be
     * opened. All strategy token holdings will be rolled forward.
     *
     * @param account the address that will reenter the vault
     * @param vault the vault to reenter
     * @param fCashToBorrow amount of fCash to borrow in the next maturity
     * @param maturity new maturity to borrow at
     */
    function rollVaultPosition(
        address account,
        address vault,
        uint256 fCashToBorrow,
        uint256 maturity,
        uint256 depositAmountExternal,
        uint32 minLendRate,
        uint32 maxBorrowRate,
        bytes calldata enterVaultData
    ) external payable returns (uint256 strategyTokensAdded);

    /**
     * @notice Prior to maturity, allows an account to withdraw their position from the vault. Will
     * redeem some number of vault shares to the borrow currency and close the borrow position by
     * lending `fCashToLend`. Any shortfall in cash from lending will be transferred from the account,
     * any excess profits will be transferred to the account.
     *
     * Post maturity, will net off the account's debt against vault cash balances and redeem all remaining
     * strategy tokens back to the borrowed currency and transfer the profits to the account.
     *
     * @param account the address that will exit the vault
     * @param vault the vault to enter
     * @param vaultSharesToRedeem amount of vault tokens to exit, only relevant when exiting pre-maturity
     * @param fCashToLend amount of fCash to lend
     * @param minLendRate the minimum rate to lend at
     * @param exitVaultData passed to the vault during exit
     * @return underlyingToReceiver amount of underlying tokens returned to the receiver on exit
     */
    function exitVault(
        address account,
        address vault,
        address receiver,
        uint256 vaultSharesToRedeem,
        uint256 fCashToLend,
        uint32 minLendRate,
        bytes calldata exitVaultData
    ) external payable returns (uint256 underlyingToReceiver);

    function settleVaultAccount(address account, address vault) external;
}

interface IVaultLiquidationAction {
    event VaultDeleverageAccount(
        address indexed vault,
        address indexed account,
        uint16 currencyId,
        uint256 vaultSharesToLiquidator,
        int256 depositAmountPrimeCash
    );

    event VaultLiquidatorProfit(
        address indexed vault,
        address indexed account,
        address indexed liquidator,
        uint256 vaultSharesToLiquidator,
        bool transferSharesToLiquidator
    );
    
    event VaultAccountCashLiquidation(
        address indexed vault,
        address indexed account,
        address indexed liquidator,
        uint16 currencyId,
        int256 fCashDeposit,
        int256 cashToLiquidator
    );

    /**
     * @notice If an account is below the minimum collateral ratio, this method wil deleverage (liquidate)
     * that account. `depositAmountExternal` in the borrow currency will be transferred from the liquidator
     * and used to offset the account's debt position. The liquidator will receive either vaultShares or
     * cash depending on the vault's configuration.
     * @param account the address that will exit the vault
     * @param vault the vault to enter
     * @param liquidator the address that will receive profits from liquidation
     * @param depositAmountPrimeCash amount of cash to deposit
     * @return vaultSharesFromLiquidation amount of vaultShares received from liquidation
     */
    function deleverageAccount(
        address account,
        address vault,
        address liquidator,
        uint16 currencyIndex,
        int256 depositUnderlyingInternal
    ) external payable returns (uint256 vaultSharesFromLiquidation, int256 depositAmountPrimeCash);

    function liquidateVaultCashBalance(
        address account,
        address vault,
        address liquidator,
        uint256 currencyIndex,
        int256 fCashDeposit
    ) external returns (int256 cashToLiquidator);

    function liquidateExcessVaultCash(
        address account,
        address vault,
        address liquidator,
        uint256 excessCashIndex,
        uint256 debtIndex,
        uint256 _depositUnderlyingInternal
    ) external payable returns (int256 cashToLiquidator);
}

interface IVaultAccountHealth {
    function getVaultAccountHealthFactors(address account, address vault) external view returns (
        VaultAccountHealthFactors memory h,
        int256[3] memory maxLiquidatorDepositUnderlying,
        uint256[3] memory vaultSharesToLiquidator
    );

    function calculateDepositAmountInDeleverage(
        uint256 currencyIndex,
        VaultAccount memory vaultAccount,
        VaultConfig memory vaultConfig,
        VaultState memory vaultState,
        int256 depositUnderlyingInternal
    ) external returns (int256 depositInternal, uint256 vaultSharesToLiquidator, PrimeRate memory);

    function getfCashRequiredToLiquidateCash(
        uint16 currencyId,
        uint256 maturity,
        int256 vaultAccountCashBalance
    ) external view returns (int256 fCashRequired, int256 discountFactor);

    function checkVaultAccountCollateralRatio(address vault, address account, bool checkDebtCap) external;

    function getVaultAccount(address account, address vault) external view returns (VaultAccount memory);
    function getVaultAccountWithFeeAccrual(
        address account, address vault
    ) external view returns (VaultAccount memory, int256 accruedPrimeVaultFeeInUnderlying);

    function getVaultConfig(address vault) external view returns (VaultConfig memory vaultConfig);

    function getBorrowCapacity(address vault, uint16 currencyId) external view returns (
        uint256 currentPrimeDebtUnderlying,
        uint256 totalfCashDebt,
        uint256 maxBorrowCapacity
    );

    function getSecondaryBorrow(address vault, uint16 currencyId, uint256 maturity) 
        external view returns (int256 totalDebt);

    /// @notice View method to get vault state
    function getVaultState(address vault, uint256 maturity) external view returns (VaultState memory vaultState);

    function getVaultAccountSecondaryDebt(address account, address vault) external view returns (
        uint256 maturity,
        int256[2] memory accountSecondaryDebt,
        int256[2] memory accountSecondaryCashHeld
    );

    function signedBalanceOfVaultTokenId(address account, uint256 id) external view returns (int256);
}

interface IVaultController is IVaultAccountAction, IVaultAction, IVaultLiquidationAction, IVaultAccountHealth {}

File 22 of 29 : nERC1155Interface.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import "../../contracts/global/Types.sol";

interface nERC1155Interface {
    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 value
    );
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);
    event URI(string value, uint256 indexed id);

    function supportsInterface(bytes4 interfaceId) external pure returns (bool);

    function balanceOf(address account, uint256 id) external view returns (uint256);

    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    function signedBalanceOf(address account, uint256 id) external view returns (int256);

    function signedBalanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (int256[] memory);

    function setApprovalForAll(address operator, bool approved) external;

    function isApprovedForAll(address account, address operator) external view returns (bool);

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external payable;

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external payable;

    function decodeToAssets(uint256[] calldata ids, uint256[] calldata amounts)
        external
        view
        returns (PortfolioAsset[] memory);

    function encodeToId(
        uint16 currencyId,
        uint40 maturity,
        uint8 assetType
    ) external pure returns (uint256 id);
}

File 23 of 29 : NotionalCalculations.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import "../../contracts/global/Types.sol";

interface NotionalCalculations {
    function calculateNTokensToMint(uint16 currencyId, uint88 amountToDepositExternalPrecision)
        external
        view
        returns (uint256);

    function nTokenPresentValueAssetDenominated(uint16 currencyId) external view returns (int256);

    function nTokenPresentValueUnderlyingDenominated(uint16 currencyId)
        external
        view
        returns (int256);

    function convertNTokenToUnderlying(uint16 currencyId, int256 nTokenBalance) external view returns (int256);

    function getfCashAmountGivenCashAmount(
        uint16 currencyId,
        int88 netCashToAccount,
        uint256 marketIndex,
        uint256 blockTime
    ) external view returns (int256);

    function getCashAmountGivenfCashAmount(
        uint16 currencyId,
        int88 fCashAmount,
        uint256 marketIndex,
        uint256 blockTime
    ) external view returns (int256, int256);

    function nTokenGetClaimableIncentives(address account, uint256 blockTime)
        external
        view
        returns (uint256);

    function getPresentfCashValue(
        uint16 currencyId,
        uint256 maturity,
        int256 notional,
        uint256 blockTime,
        bool riskAdjusted
    ) external view returns (int256 presentValue);

    function getMarketIndex(
        uint256 maturity,
        uint256 blockTime
    ) external pure returns (uint8 marketIndex);

    function getfCashLendFromDeposit(
        uint16 currencyId,
        uint256 depositAmountExternal,
        uint256 maturity,
        uint32 minLendRate,
        uint256 blockTime,
        bool useUnderlying
    ) external view returns (
        uint88 fCashAmount,
        uint8 marketIndex,
        bytes32 encodedTrade
    );

    function getfCashBorrowFromPrincipal(
        uint16 currencyId,
        uint256 borrowedAmountExternal,
        uint256 maturity,
        uint32 maxBorrowRate,
        uint256 blockTime,
        bool useUnderlying
    ) external view returns (
        uint88 fCashDebt,
        uint8 marketIndex,
        bytes32 encodedTrade
    );

    function getDepositFromfCashLend(
        uint16 currencyId,
        uint256 fCashAmount,
        uint256 maturity,
        uint32 minLendRate,
        uint256 blockTime
    ) external view returns (
        uint256 depositAmountUnderlying,
        uint256 depositAmountAsset,
        uint8 marketIndex,
        bytes32 encodedTrade
    );

    function getPrincipalFromfCashBorrow(
        uint16 currencyId,
        uint256 fCashBorrow,
        uint256 maturity,
        uint32 maxBorrowRate,
        uint256 blockTime
    ) external view returns (
        uint256 borrowAmountUnderlying,
        uint256 borrowAmountAsset,
        uint8 marketIndex,
        bytes32 encodedTrade
    );

    function convertCashBalanceToExternal(
        uint16 currencyId,
        int256 cashBalanceInternal,
        bool useUnderlying
    ) external view returns (int256);

    function convertUnderlyingToPrimeCash(
        uint16 currencyId,
        int256 underlyingExternal
    ) external view returns (int256);

    function convertSettledfCash(
        uint16 currencyId,
        uint256 maturity,
        int256 fCashBalance,
        uint256 blockTime
    ) external view returns (int256 signedPrimeSupplyValue);

    function accruePrimeInterest(
        uint16 currencyId
    ) external returns (PrimeRate memory pr, PrimeCashFactors memory);
}

File 24 of 29 : NotionalGovernance.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import "../../contracts/global/Deployments.sol";
import "../../contracts/global/Types.sol";
import "../../interfaces/chainlink/AggregatorV2V3Interface.sol";
import "../../interfaces/notional/NotionalGovernance.sol";
import "../../interfaces/notional/IRewarder.sol";
import "../../interfaces/aave/ILendingPool.sol";
import {IPrimeCashHoldingsOracle} from "../../interfaces/notional/IPrimeCashHoldingsOracle.sol";

interface NotionalGovernance {
    event ListCurrency(uint16 newCurrencyId);
    event UpdateETHRate(uint16 currencyId);
    event UpdateAssetRate(uint16 currencyId);
    event UpdateCashGroup(uint16 currencyId);
    event DeployNToken(uint16 currencyId, address nTokenAddress);
    event UpdateDepositParameters(uint16 currencyId);
    event UpdateInitializationParameters(uint16 currencyId);
    event UpdateTokenCollateralParameters(uint16 currencyId);
    event UpdateGlobalTransferOperator(address operator, bool approved);
    event UpdateAuthorizedCallbackContract(address operator, bool approved);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event PauseRouterAndGuardianUpdated(address indexed pauseRouter, address indexed pauseGuardian);
    event UpdateInterestRateCurve(uint16 indexed currencyId, uint8 indexed marketIndex);
    event UpdateMaxUnderlyingSupply(uint16 indexed currencyId, uint256 maxUnderlyingSupply);
    event PrimeProxyDeployed(uint16 indexed currencyId, address proxy, bool isCashProxy);

    function transferOwnership(address newOwner, bool direct) external;

    function claimOwnership() external;

    function upgradeBeacon(Deployments.BeaconType proxy, address newBeacon) external;

    function setPauseRouterAndGuardian(address pauseRouter_, address pauseGuardian_) external;

    function listCurrency(
        TokenStorage calldata underlyingToken,
        ETHRateStorage memory ethRate,
        InterestRateCurveSettings calldata primeDebtCurve,
        IPrimeCashHoldingsOracle primeCashHoldingsOracle,
        bool allowPrimeCashDebt,
        uint8 rateOracleTimeWindow5Min,
        string calldata underlyingName,
        string calldata underlyingSymbol
    ) external returns (uint16 currencyId);

    function enableCashGroup(
        uint16 currencyId,
        CashGroupSettings calldata cashGroup,
        string calldata underlyingName,
        string calldata underlyingSymbol
    ) external;

    function updateDepositParameters(
        uint16 currencyId,
        uint32[] calldata depositShares,
        uint32[] calldata leverageThresholds
    ) external;

    function updateInitializationParameters(
        uint16 currencyId,
        uint32[] calldata annualizedAnchorRates,
        uint32[] calldata proportions
    ) external;


    function updateTokenCollateralParameters(
        uint16 currencyId,
        uint8 residualPurchaseIncentive10BPS,
        uint8 pvHaircutPercentage,
        uint8 residualPurchaseTimeBufferHours,
        uint8 cashWithholdingBuffer10BPS,
        uint8 liquidationHaircutPercentage,
        uint8 maxMintDeviationPercentage
    ) external;

    function updateCashGroup(uint16 currencyId, CashGroupSettings calldata cashGroup) external;

    function updateInterestRateCurve(
        uint16 currencyId,
        uint8[] calldata marketIndices,
        InterestRateCurveSettings[] calldata settings
    ) external;

    function setMaxUnderlyingSupply(
        uint16 currencyId,
        uint256 maxUnderlyingSupply,
        uint8 maxPrimeDebtUtilization
    ) external;

    function updatePrimeCashHoldingsOracle(
        uint16 currencyId,
        IPrimeCashHoldingsOracle primeCashHoldingsOracle
    ) external;

    function updatePrimeCashCurve(
        uint16 currencyId,
        InterestRateCurveSettings calldata primeDebtCurve
    ) external;

    function enablePrimeDebt(
        uint16 currencyId,
        string calldata underlyingName,
        string calldata underlyingSymbol
    ) external;

    function updateETHRate(
        uint16 currencyId,
        AggregatorV2V3Interface rateOracle,
        bool mustInvert,
        uint8 buffer,
        uint8 haircut,
        uint8 liquidationDiscount
    ) external;

    function updateAuthorizedCallbackContract(address operator, bool approved) external;
}

File 25 of 29 : NotionalProxy.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import "../../contracts/global/Types.sol";
import "./nTokenERC20.sol";
import "./nERC1155Interface.sol";
import "./NotionalGovernance.sol";
import "./NotionalCalculations.sol";
import "./NotionalViews.sol";
import "./NotionalTreasury.sol";
import {IVaultController} from "./IVaultController.sol";

interface NotionalProxy is
    nTokenERC20,
    nERC1155Interface,
    NotionalGovernance,
    NotionalTreasury,
    NotionalCalculations,
    NotionalViews,
    IVaultController
{
    /** User trading events */
    event MarketsInitialized(uint16 currencyId);
    event SweepCashIntoMarkets(uint16 currencyId, int256 cashIntoMarkets);

    /// @notice Emitted once when incentives are migrated
    event IncentivesMigrated(
        uint16 currencyId,
        uint256 migrationEmissionRate,
        uint256 finalIntegralTotalSupply,
        uint256 migrationTime
    );
    /// @notice Emitted if a token address is migrated
    event TokenMigrated(uint16 currencyId) ;
    /// @notice Emitted whenever an account context has updated
    event AccountContextUpdate(address indexed account);
    /// @notice Emitted when an account has assets that are settled
    event AccountSettled(address indexed account);

    /* Liquidation Events */
    event LiquidateLocalCurrency(
        address indexed liquidated,
        address indexed liquidator,
        uint16 localCurrencyId,
        int256 netLocalFromLiquidator
    );

    event LiquidateCollateralCurrency(
        address indexed liquidated,
        address indexed liquidator,
        uint16 localCurrencyId,
        uint16 collateralCurrencyId,
        int256 netLocalFromLiquidator,
        int256 netCollateralTransfer,
        int256 netNTokenTransfer
    );

    event LiquidatefCashEvent(
        address indexed liquidated,
        address indexed liquidator,
        uint16 localCurrencyId,
        uint16 fCashCurrency,
        int256 netLocalFromLiquidator,
        uint256[] fCashMaturities,
        int256[] fCashNotionalTransfer
    );

    event SetPrimeSettlementRate(
        uint256 indexed currencyId,
        uint256 indexed maturity,
        int256 supplyFactor,
        int256 debtFactor
    );

    /// @notice Emits every time interest is accrued
    event PrimeCashInterestAccrued(
        uint16 indexed currencyId,
        uint256 underlyingScalar,
        uint256 supplyScalar,
        uint256 debtScalar
    );

    event PrimeCashCurveChanged(uint16 indexed currencyId);

    event PrimeCashHoldingsOracleUpdated(uint16 indexed currencyId, address oracle);

    /** UUPS Upgradeable contract calls */
    function upgradeTo(address newImplementation) external;

    function upgradeToAndCall(address newImplementation, bytes memory data) external payable;

    function getImplementation() external view returns (address);

    function owner() external view returns (address);

    function pauseRouter() external view returns (address);

    function pauseGuardian() external view returns (address);

    /** Initialize Markets Action */
    function initializeMarkets(uint16 currencyId, bool isFirstInit) external;

    function sweepCashIntoMarkets(uint16 currencyId) external;

    /** Account Action */
    function nTokenRedeem(
        address redeemer,
        uint16 currencyId,
        uint96 tokensToRedeem_
    ) external returns (int256);

    function enablePrimeBorrow(bool allowPrimeBorrow) external;

    function enableBitmapCurrency(uint16 currencyId) external;

    function settleAccount(address account) external;

    function depositUnderlyingToken(
        address account,
        uint16 currencyId,
        uint256 amountExternalPrecision
    ) external payable returns (uint256);

    function withdraw(
        uint16 currencyId,
        uint88 amountInternalPrecision,
        bool redeemToUnderlying
    ) external returns (uint256);

    function withdrawViaProxy(
        uint16 currencyId,
        address owner,
        address receiver,
        address spender,
        uint88 withdrawAmountPrimeCash
    ) external returns (uint256);

    /** Batch Action */
    function batchBalanceAction(address account, BalanceAction[] calldata actions) external payable;

    function batchBalanceAndTradeAction(address account, BalanceActionWithTrades[] calldata actions)
        external
        payable;

    function batchBalanceAndTradeActionWithCallback(
        address account,
        BalanceActionWithTrades[] calldata actions,
        bytes calldata callbackData
    ) external payable;

    function batchLend(address account, BatchLend[] calldata actions) external;

    /** Liquidation Action */
    function calculateLocalCurrencyLiquidation(
        address liquidateAccount,
        uint16 localCurrency,
        uint96 maxNTokenLiquidation
    ) external returns (int256, int256);

    function liquidateLocalCurrency(
        address liquidateAccount,
        uint16 localCurrency,
        uint96 maxNTokenLiquidation
    ) external payable returns (int256, int256);

    function calculateCollateralCurrencyLiquidation(
        address liquidateAccount,
        uint16 localCurrency,
        uint16 collateralCurrency,
        uint128 maxCollateralLiquidation,
        uint96 maxNTokenLiquidation
    ) external returns (int256, int256, int256);

    function liquidateCollateralCurrency(
        address liquidateAccount,
        uint16 localCurrency,
        uint16 collateralCurrency,
        uint128 maxCollateralLiquidation,
        uint96 maxNTokenLiquidation,
        bool withdrawCollateral,
        bool redeemToUnderlying
    ) external payable returns (int256, int256, int256);

    function calculatefCashLocalLiquidation(
        address liquidateAccount,
        uint16 localCurrency,
        uint256[] calldata fCashMaturities,
        uint256[] calldata maxfCashLiquidateAmounts
    ) external returns (int256[] memory, int256);

    function liquidatefCashLocal(
        address liquidateAccount,
        uint16 localCurrency,
        uint256[] calldata fCashMaturities,
        uint256[] calldata maxfCashLiquidateAmounts
    ) external payable returns (int256[] memory, int256);

    function calculatefCashCrossCurrencyLiquidation(
        address liquidateAccount,
        uint16 localCurrency,
        uint16 fCashCurrency,
        uint256[] calldata fCashMaturities,
        uint256[] calldata maxfCashLiquidateAmounts
    ) external returns (int256[] memory, int256);

    function liquidatefCashCrossCurrency(
        address liquidateAccount,
        uint16 localCurrency,
        uint16 fCashCurrency,
        uint256[] calldata fCashMaturities,
        uint256[] calldata maxfCashLiquidateAmounts
    ) external payable returns (int256[] memory, int256);
}

File 26 of 29 : NotionalTreasury.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import {IRewarder} from "./IRewarder.sol";

interface NotionalTreasury {
    event UpdateIncentiveEmissionRate(uint16 currencyId, uint32 newEmissionRate);
    event UpdateSecondaryIncentiveRewarder(uint16 indexed currencyId, address rewarder);

    struct RebalancingTargetConfig {
        address holding;
        uint8 targetUtilization;
        uint16 externalWithdrawThreshold;
    }

    /// @notice Emitted when reserve balance is updated
    event ReserveBalanceUpdated(uint16 indexed currencyId, int256 newBalance);
    /// @notice Emitted when reserve balance is harvested
    event ExcessReserveBalanceHarvested(uint16 indexed currencyId, int256 harvestAmount);
    /// @dev Emitted when treasury manager is updated
    event TreasuryManagerChanged(address indexed previousManager, address indexed newManager);
    /// @dev Emitted when reserve buffer value is updated
    event ReserveBufferUpdated(uint16 currencyId, uint256 bufferAmount);

    event RebalancingTargetsUpdated(uint16 currencyId, RebalancingTargetConfig[] targets);

    event RebalancingCooldownUpdated(uint16 currencyId, uint40 cooldownTimeInSeconds);

    event CurrencyRebalanced(uint16 currencyId, uint256 supplyFactor, uint256 annualizedInterestRate);

    /// @notice Emitted when the interest accrued on asset deposits is harvested 
    event AssetInterestHarvested(uint16 indexed currencyId, address assetToken, uint256 harvestAmount);

    function transferReserveToTreasury(uint16[] calldata currencies) external returns (uint256[] memory);

    function harvestAssetInterest(uint16[] calldata currencies) external;

    function setTreasuryManager(address manager) external;

    function setRebalancingBot(address _rebalancingBot) external;

    function setReserveBuffer(uint16 currencyId, uint256 amount) external;

    function setReserveCashBalance(uint16 currencyId, int256 reserveBalance) external;

    function setRebalancingTargets(uint16 currencyId, RebalancingTargetConfig[] calldata targets) external;

    function setRebalancingCooldown(uint16 currencyId, uint40 cooldownTimeInSeconds) external;

    function checkRebalance() external view returns (uint16[] memory currencyIds);

    function rebalance(uint16 currencyId) external;

    function updateIncentiveEmissionRate(uint16 currencyId, uint32 newEmissionRate) external;

    function setSecondaryIncentiveRewarder(uint16 currencyId, IRewarder rewarder) external;
}

File 27 of 29 : NotionalViews.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

import "../../contracts/global/Types.sol";

interface NotionalViews {
    function getMaxCurrencyId() external view returns (uint16);

    function getCurrencyId(address tokenAddress) external view returns (uint16 currencyId);

    function getCurrency(uint16 currencyId)
        external
        view
        returns (Token memory assetToken, Token memory underlyingToken);

    function getRateStorage(uint16 currencyId)
        external
        view
        returns (ETHRateStorage memory ethRate, AssetRateStorage memory assetRate);

    function getCurrencyAndRates(uint16 currencyId)
        external
        view
        returns (
            Token memory assetToken,
            Token memory underlyingToken,
            ETHRate memory ethRate,
            Deprecated_AssetRateParameters memory assetRate
        );

    function getCashGroup(uint16 currencyId) external view returns (CashGroupSettings memory);

    function getCashGroupAndAssetRate(uint16 currencyId)
        external
        view
        returns (CashGroupSettings memory cashGroup, Deprecated_AssetRateParameters memory assetRate);

    function getInterestRateCurve(uint16 currencyId) external view returns (
        InterestRateParameters[] memory nextInterestRateCurve,
        InterestRateParameters[] memory activeInterestRateCurve
    );

    function getInitializationParameters(uint16 currencyId)
        external
        view
        returns (int256[] memory annualizedAnchorRates, int256[] memory proportions);

    function getDepositParameters(uint16 currencyId)
        external
        view
        returns (int256[] memory depositShares, int256[] memory leverageThresholds);

    function nTokenAddress(uint16 currencyId) external view returns (address);

    function pCashAddress(uint16 currencyId) external view returns (address);

    function pDebtAddress(uint16 currencyId) external view returns (address);

    function getNoteToken() external view returns (address);

    function getOwnershipStatus() external view returns (address owner, address pendingOwner);

    function getGlobalTransferOperatorStatus(address operator)
        external
        view
        returns (bool isAuthorized);

    function getAuthorizedCallbackContractStatus(address callback)
        external
        view
        returns (bool isAuthorized);

    function getSecondaryIncentiveRewarder(uint16 currencyId)
        external
        view
        returns (address incentiveRewarder);

    function getPrimeFactors(uint16 currencyId, uint256 blockTime) external view returns (
        PrimeRate memory primeRate,
        PrimeCashFactors memory factors,
        uint256 maxUnderlyingSupply,
        uint256 totalUnderlyingSupply,
        uint256 maxUnderlyingDebt,
        uint256 totalUnderlyingDebt
    );

    function getPrimeFactorsStored(uint16 currencyId) external view returns (PrimeCashFactors memory);

    function getPrimeCashHoldingsOracle(uint16 currencyId) external view returns (address);

    function getPrimeInterestRateCurve(uint16 currencyId) external view returns (InterestRateParameters memory);

    function getPrimeInterestRate(uint16 currencyId) external view returns (
        uint256 annualDebtRatePreFee,
        uint256 annualDebtRatePostFee,
        uint256 annualSupplyRate
    );

    function getTotalfCashDebtOutstanding(uint16 currencyId, uint256 maturity) external view returns (
        int256 totalfCashDebt,
        int256 fCashDebtHeldInSettlementReserve,
        int256 primeCashHeldInSettlementReserve
    );

    function getSettlementRate(uint16 currencyId, uint40 maturity)
        external
        view
        returns (PrimeRate memory);

    function getMarket(
        uint16 currencyId,
        uint256 maturity,
        uint256 settlementDate
    ) external view returns (MarketParameters memory);

    function getActiveMarkets(uint16 currencyId) external view returns (MarketParameters[] memory);

    function getActiveMarketsAtBlockTime(uint16 currencyId, uint32 blockTime)
        external
        view
        returns (MarketParameters[] memory);

    function getReserveBalance(uint16 currencyId) external view returns (int256 reserveBalance);

    function getNTokenPortfolio(address tokenAddress)
        external
        view
        returns (PortfolioAsset[] memory liquidityTokens, PortfolioAsset[] memory netfCashAssets);

    function getNTokenAccount(address tokenAddress)
        external
        view
        returns (
            uint16 currencyId,
            uint256 totalSupply,
            uint256 incentiveAnnualEmissionRate,
            uint256 lastInitializedTime,
            bytes6 nTokenParameters,
            int256 cashBalance,
            uint256 accumulatedNOTEPerNToken,
            uint256 lastAccumulatedTime
        );

    function getAccount(address account)
        external
        view
        returns (
            AccountContext memory accountContext,
            AccountBalance[] memory accountBalances,
            PortfolioAsset[] memory portfolio
        );

    function getAccountContext(address account) external view returns (AccountContext memory);

    function getAccountPrimeDebtBalance(uint16 currencyId, address account) external view returns (
        int256 debtBalance
    );

    function getAccountBalance(uint16 currencyId, address account)
        external
        view
        returns (
            int256 cashBalance,
            int256 nTokenBalance,
            uint256 lastClaimTime
        );

    function getBalanceOfPrimeCash(
        uint16 currencyId,
        address account
    ) external view returns (int256 cashBalance);

    function getAccountPortfolio(address account) external view returns (PortfolioAsset[] memory);

    function getfCashNotional(
        address account,
        uint16 currencyId,
        uint256 maturity
    ) external view returns (int256);

    function getAssetsBitmap(address account, uint16 currencyId) external view returns (bytes32);

    function getFreeCollateral(address account) external view returns (int256, int256[] memory);

    function getTreasuryManager() external view returns (address);

    function getReserveBuffer(uint16 currencyId) external view returns (uint256);

    function getRebalancingFactors(uint16 currencyId) external view
      returns (address holding, uint8 target, uint16 externalWithdrawThreshold, RebalancingContextStorage memory context);

    function getStoredTokenBalances(address[] calldata tokens) external view returns (uint256[] memory balances);

    function decodeERC1155Id(uint256 id) external view returns (
        uint16 currencyId,
        uint256 maturity,
        uint256 assetType,
        address vaultAddress,
        bool isfCashDebt
    );

    function encode(
        uint16 currencyId,
        uint256 maturity,
        uint256 assetType,
        address vaultAddress,
        bool isfCashDebt
    ) external pure returns (uint256);
}

File 28 of 29 : nTokenERC20.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;
pragma abicoder v2;

interface nTokenERC20 {
    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    function nTokenTotalSupply(address nTokenAddress) external view returns (uint256);

    function nTokenBalanceOf(uint16 currencyId, address account) external view returns (uint256);

    function nTokenTransferAllowance(
        uint16 currencyId,
        address owner,
        address spender
    ) external view returns (uint256);

    function pCashTransferAllowance(
        uint16 currencyId,
        address owner,
        address spender
    ) external view returns (uint256);

    function nTokenTransferApprove(
        uint16 currencyId,
        address owner,
        address spender,
        uint256 amount
    ) external returns (bool);

    function pCashTransferApprove(
        uint16 currencyId,
        address owner,
        address spender,
        uint256 amount
    ) external returns (bool);

    function nTokenTransfer(
        uint16 currencyId,
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    function pCashTransfer(
        uint16 currencyId,
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    function nTokenTransferFrom(
        uint16 currencyId,
        address spender,
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    function pCashTransferFrom(
        uint16 currencyId,
        address spender,
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    function nTokenTransferApproveAll(address spender, uint256 amount) external returns (bool);

    function nTokenClaimIncentives() external returns (uint256);

}

File 29 of 29 : WETH9.sol
// SPDX-License-Identifier: BSUL-1.1
pragma solidity >=0.7.6;

interface WETH9 {
    function deposit() external payable;

    function withdraw(uint256 wad) external;

    function transfer(address dst, uint256 wad) external returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract NotionalProxy","name":"notional","type":"address"},{"internalType":"uint16","name":"currencyId","type":"uint16"},{"internalType":"contract IERC20","name":"incentive_token","type":"address"},{"internalType":"uint128","name":"_emissionRatePerYear","type":"uint128"},{"internalType":"uint32","name":"_endTime","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"emissionRatePerYear","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"RewardEmissionUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardTransfer","type":"event"},{"inputs":[],"name":"CURRENCY_ID","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NOTIONAL","outputs":[{"internalType":"contract NotionalProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NTOKEN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_TOKEN_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accumulatedRewardPerNToken","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint16","name":"currencyId","type":"uint16"},{"internalType":"uint256","name":"nTokenBalanceBefore","type":"uint256"},{"internalType":"uint256","name":"nTokenBalanceAfter","type":"uint256"},{"internalType":"uint256","name":"priorNTokenSupply","type":"uint256"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"nTokenBalanceAtDetach","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claimRewardsDirect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"detach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"detached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emissionRatePerYear","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"nTokenBalanceAtDetach","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"getAccountRewardClaim","outputs":[{"internalType":"uint256","name":"rewardToClaim","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"blockTime","type":"uint32"}],"name":"getAccountRewardClaim","outputs":[{"internalType":"uint256","name":"rewardToClaim","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastAccumulatedTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardDebtPerAccount","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"_emissionRatePerYear","type":"uint128"},{"internalType":"uint32","name":"_endTime","type":"uint32"}],"name":"setIncentiveEmissionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101206040523480156200001257600080fd5b5060405162001c7238038062001c72833981810160405260a08110156200003857600080fd5b5080516020808301516040808501516060808701516080978801519187901b6001600160601b03191690975260f084901b6001600160f01b0319166101005282516325d2c41560e21b815261ffff85166004820152925195969395919490926001600160a01b0388169263974b105492602480840193919291829003018186803b158015620000c657600080fd5b505afa158015620000db573d6000803e3d6000fd5b505050506040513d6020811015620000f257600080fd5b50516001600160601b0319606091821b811660a0529084901b1660c0526040805163313ce56760e01b815290516001600160a01b0385169163313ce567916004808301926020929190829003018186803b1580156200015057600080fd5b505afa15801562000165573d6000803e3d6000fd5b505050506040513d60208110156200017c57600080fd5b505160f81b7fff000000000000000000000000000000000000000000000000000000000000001660e052620001c66001600160801b03831662000291602090811b620010ad17901c565b6001805466ffffffffffffff60481b1916690100000000000000000066ffffffffffffff93909316929092029190911763ffffffff60281b1916650100000000004263ffffffff908116820292909217928390558382169204161062000266576040805162461bcd60e51b815260206004820152601060248201526f496e76616c696420456e642054696d6560801b604482015290519081900360640190fd5b6001805463ffffffff9092166101000264ffffffff0019909216919091179055506200037592505050565b60008065ffffffffffff831115620002bf57602f620002bb84620002ce60201b620010dc1760201c565b0390505b82811c60081b1790505b919050565b600081620002db57600080fd5b600160801b8210620002ef57608091821c91015b6801000000000000000082106200030857604091821c91015b64010000000082106200031d57602091821c91015b6201000082106200033057601091821c91015b61010082106200034257600891821c91015b601082106200035357600491821c91015b600482106200036457600291821c91015b60028210620002c957600101919050565b60805160601c60a05160601c60c05160601c60e05160f81c6101005160f01c61186d6200040560003980610a595280610dcf5250806104585280611535525080610d9552806112e752806113945250806105f25280610790528061086e5280610f225280610fcd5250806104df52806107bd52806109b25280610b015280610c475280610d71525061186d6000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80635705ae43116100ad5780639c07e54c116100715780639c07e54c146103705780639d4be3f514610378578063a105fc9614610397578063dacf76bd1461041c578063dadff3c41461044e5761012c565b80635705ae43146102d55780637cb64759146103015780637d43702f1461031e578063858dccb31461036057806399248ea7146103685761012c565b80632eb4a7ab116100f45780632eb4a7ab146102345780633197cbb61461024e5780633f3ef50d1461026f578063432cc1b3146102b15780634fd371e3146102cd5761012c565b80630330d663146101315780630537b3571461014f5780630e1e772f146101d65780631c92197614610208578063225435c01461022c575b600080fd5b610139610456565b6040805160ff9092168252519081900360200190f35b6101d46004803603606081101561016557600080fd5b6001600160a01b038235169160208101359181019060608101604082013564010000000081111561019557600080fd5b8201836020820111156101a757600080fd5b803590602001918460208302840111640100000000831117156101c957600080fd5b50909250905061047a565b005b6101d4600480360360408110156101ec57600080fd5b5080356001600160801b0316906020013563ffffffff166104dd565b61021061078e565b604080516001600160a01b039092168252519081900360200190f35b6101d46107b2565b61023c610990565b60408051918252519081900360200190f35b610256610996565b6040805163ffffffff9092168252519081900360200190f35b6101d4600480360360a081101561028557600080fd5b506001600160a01b038135169061ffff60208201351690604081013590606081013590608001356109a7565b6102b9610ae3565b604080519115158252519081900360200190f35b610256610aec565b6101d4600480360360408110156102eb57600080fd5b506001600160a01b038135169060200135610aff565b6101d46004803603602081101561031757600080fd5b5035610c45565b6103446004803603602081101561033457600080fd5b50356001600160a01b0316610d54565b604080516001600160801b039092168252519081900360200190f35b610210610d6f565b610210610d93565b610344610db7565b610380610dcd565b6040805161ffff9092168252519081900360200190f35b61023c600480360360608110156103ad57600080fd5b6001600160a01b03823516916020810135918101906060810160408201356401000000008111156103dd57600080fd5b8201836020820111156103ef57600080fd5b8035906020019184602083028401116401000000008311171561041157600080fd5b509092509050610df1565b61023c6004803603604081101561043257600080fd5b5080356001600160a01b0316906020013563ffffffff16610e7c565b610344611089565b7f000000000000000000000000000000000000000000000000000000000000000081565b60015460ff166104c0576040805162461bcd60e51b815260206004820152600c60248201526b139bdd0819195d1858da195960a21b604482015290519081900360640190fd5b6104cc8484848461117a565b6104d7848485611244565b50505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561053657600080fd5b505afa15801561054a573d6000803e3d6000fd5b505050506040513d602081101561056057600080fd5b50516001600160a01b031633146105ab576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015290519081900360640190fd5b60015460ff16156105ee576040805162461bcd60e51b815260206004820152600860248201526711195d1858da195960c21b604482015290519081900360640190fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561064957600080fd5b505afa15801561065d573d6000803e3d6000fd5b505050506040513d602081101561067357600080fd5b5051905061068142826113fa565b610693836001600160801b03166110ad565b6001805466ffffffffffffff92909216600160481b0266ffffffffffffff60481b19909216919091179081905563ffffffff808416600160281b9092041610610716576040805162461bcd60e51b815260206004820152601060248201526f496e76616c696420456e642054696d6560801b604482015290519081900360640190fd5b6001805464ffffffff00191661010063ffffffff85160217908190557f5208ab6d453e25ff339785d249c1622a65a099886cb31e91ba4bce4987d3316c9061076d90600160481b900466ffffffffffffff1661147c565b6040805191825263ffffffff851660208301528051918290030190a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461081f576040805162461bcd60e51b815260206004820152600d60248201526c13db9b1e48139bdd1a5bdb985b609a1b604482015290519081900360640190fd5b60015460ff161561086a576040805162461bcd60e51b815260206004820152601060248201526f105b1c9958591e4819195d1858da195960821b604482015290519081900360640190fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108c557600080fd5b505afa1580156108d9573d6000803e3d6000fd5b505050506040513d60208110156108ef57600080fd5b505190506108fd42826113fa565b6001805460ff1916811766ffffffffffffff60481b191690819055610100900463ffffffff16421015610945576001805464ffffffff0019166101004263ffffffff16021790555b600154604080516000815261010090920463ffffffff16602083015280517f5208ab6d453e25ff339785d249c1622a65a099886cb31e91ba4bce4987d3316c9281900390910190a150565b60005481565b600154610100900463ffffffff1681565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a14576040805162461bcd60e51b815260206004820152600d60248201526c13db9b1e48139bdd1a5bdb985b609a1b604482015290519081900360640190fd5b60015460ff1615610a57576040805162461bcd60e51b815260206004820152600860248201526711195d1858da195960c21b604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000061ffff168461ffff1614610ac7576040805162461bcd60e51b815260206004820152601160248201527015dc9bdb99c818dd5c9c995b98de481a59607a1b604482015290519081900360640190fd5b610ad142826113fa565b610adc858484611244565b5050505050565b60015460ff1681565b600154600160281b900463ffffffff1681565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b5857600080fd5b505afa158015610b6c573d6000803e3d6000fd5b505050506040513d6020811015610b8257600080fd5b50516001600160a01b03163314610bcd576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015290519081900360640190fd5b6001600160a01b038216610c3657604051600090339083908381818185875af1925050503d8060008114610c1d576040519150601f19603f3d011682016040523d82523d6000602084013e610c22565b606091505b5050905080610c3057600080fd5b50610c41565b610c4182338361148a565b5050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c9e57600080fd5b505afa158015610cb2573d6000803e3d6000fd5b505050506040513d6020811015610cc857600080fd5b50516001600160a01b03163314610d13576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015290519081900360640190fd5b80610d4f576040805162461bcd60e51b8152602060048201526007602482015266125b9d985b1a5960ca1b604482015290519081900360640190fd5b600055565b6002602052600090815260409020546001600160801b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b600154600160801b90046001600160801b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b60015460009060ff168015610e07575060005415155b610e47576040805162461bcd60e51b815260206004820152600c60248201526b139bdd0819195d1858da195960a21b604482015290519081900360640190fd5b610e538585858561117a565b610e738585600160109054906101000a90046001600160801b0316611506565b95945050505050565b60015460009060ff1615610ec2576040805162461bcd60e51b815260206004820152600860248201526711195d1858da195960c21b604482015290519081900360640190fd5b60015463ffffffff808416600160281b909204161115610f1e576040805162461bcd60e51b8152602060048201526012602482015271496e76616c696420626c6f636b2074696d6560701b604482015290519081900360640190fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f7957600080fd5b505afa158015610f8d573d6000803e3d6000fd5b505050506040513d6020811015610fa357600080fd5b5051604080516370a0823160e01b81526001600160a01b03878116600483015291519293506000927f0000000000000000000000000000000000000000000000000000000000000000909216916370a0823191602480820192602092909190829003018186803b15801561101657600080fd5b505afa15801561102a573d6000803e3d6000fd5b505050506040513d602081101561104057600080fd5b50516001549091506000906110639063ffffffff80881691610100900416611592565b9050600061107182856115ac565b905061107e878483611506565b979650505050505050565b6001546000906110a890600160481b900466ffffffffffffff1661147c565b905090565b60008065ffffffffffff8311156110cd57602f6110c9846110dc565b0390505b82811c60081b1790505b919050565b6000816110e857600080fd5b600160801b82106110fb57608091821c91015b68010000000000000000821061111357604091821c91015b640100000000821061112757602091821c91015b62010000821061113957601091821c91015b610100821061114a57600891821c91015b6010821061115a57600491821c91015b6004821061116a57600291821c91015b600282106110d757600101919050565b6000848460405160200180836001600160a01b031660601b81526014018281526020019250505060405160208183030381529060405280519060200120905060006111fa84848080602002602001604051908101604052809392919081815260200183836020028082843760009201829052505492508691506116419050565b90508061123c576040805162461bcd60e51b815260206004820152600b60248201526a4e6f74496e4d65726b6c6560a81b604482015290519081900360640190fd5b505050505050565b60006112668484600160109054906101000a90046001600160801b0316611506565b6001549091506112a09061129b906305f5e10090611295908690600160801b90046001600160801b03166116ea565b90611711565b611730565b6001600160a01b038516600090815260026020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b039290921691909117905580156104d7577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561135c57600080fd5b505af192505050801561136d575060015b611376576104d7565b600061138061174a565b90508015610adc57846001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167fa282a314ffba449688a7c5eb4426bd8e1781944ce824ce34dfaea4691d08f146846040518082815260200191505060405180910390a35050505050565b600154610100900463ffffffff1661141157600080fd5b60015460009061142f9063ffffffff80861691610100900416611592565b905061143b81836115ac565b6001805463ffffffff4216600160281b0268ffffffff0000000000196001600160801b03948516600160801b02949092169390931716919091179055505050565b600881901c60ff9091161b90565b826001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156114e157600080fd5b505af11580156114f5573d6000803e3d6000fd5b50505050611501611785565b505050565b6001600160a01b03831660009081526002602052604081205461158a90670de0b6b3a7640000906112959060ff7f000000000000000000000000000000000000000000000000000000000000000016600a0a90611584906001600160801b039081169061157e906305f5e1009086908c908c166116ea565b906117f2565b906116ea565b949350505050565b60008183126115a157816115a3565b825b90505b92915050565b600154600090819063ffffffff808616600160281b909204161080156115d25750826000105b156116205760015463ffffffff600160281b909104811685031661161c846112956301da9c0081611601611089565b6001600160801b031661158487670de0b6b3a76400006116ea565b9150505b60015461158a9061129b90600160801b90046001600160801b031683611807565b600081815b85518110156116df57600086828151811061165d57fe5b602002602001015190508083116116a457828160405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092506116d6565b808360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b50600101611646565b509092149392505050565b6000826116f9575060006115a6565b8282028284828161170657fe5b04146115a357600080fd5b600080821161171f57600080fd5b81838161172857fe5b049392505050565b60006001600160801b0382111561174657600080fd5b5090565b6000611754611819565b3d801561176c57602081146117755760009250611780565b60019250611780565b60206000833e815192505b505090565b600061178f611819565b3d80156117a357602081146117ac57600080fd5b600192506117b7565b60206000833e815192505b5081610c41576040805162461bcd60e51b8152602060048201526005602482015264045524332360dc1b604482015290519081900360640190fd5b60008282111561180157600080fd5b50900390565b6000828201838110156115a357600080fd5b6040518060200160405280600190602082028036833750919291505056fea2646970667358221220a74639935b148d816e897ebe75f8648de6b80ed7bd5ef4f5bd1ebdddbd81bddb64736f6c634300070600330000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066c92280

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061012c5760003560e01c80635705ae43116100ad5780639c07e54c116100715780639c07e54c146103705780639d4be3f514610378578063a105fc9614610397578063dacf76bd1461041c578063dadff3c41461044e5761012c565b80635705ae43146102d55780637cb64759146103015780637d43702f1461031e578063858dccb31461036057806399248ea7146103685761012c565b80632eb4a7ab116100f45780632eb4a7ab146102345780633197cbb61461024e5780633f3ef50d1461026f578063432cc1b3146102b15780634fd371e3146102cd5761012c565b80630330d663146101315780630537b3571461014f5780630e1e772f146101d65780631c92197614610208578063225435c01461022c575b600080fd5b610139610456565b6040805160ff9092168252519081900360200190f35b6101d46004803603606081101561016557600080fd5b6001600160a01b038235169160208101359181019060608101604082013564010000000081111561019557600080fd5b8201836020820111156101a757600080fd5b803590602001918460208302840111640100000000831117156101c957600080fd5b50909250905061047a565b005b6101d4600480360360408110156101ec57600080fd5b5080356001600160801b0316906020013563ffffffff166104dd565b61021061078e565b604080516001600160a01b039092168252519081900360200190f35b6101d46107b2565b61023c610990565b60408051918252519081900360200190f35b610256610996565b6040805163ffffffff9092168252519081900360200190f35b6101d4600480360360a081101561028557600080fd5b506001600160a01b038135169061ffff60208201351690604081013590606081013590608001356109a7565b6102b9610ae3565b604080519115158252519081900360200190f35b610256610aec565b6101d4600480360360408110156102eb57600080fd5b506001600160a01b038135169060200135610aff565b6101d46004803603602081101561031757600080fd5b5035610c45565b6103446004803603602081101561033457600080fd5b50356001600160a01b0316610d54565b604080516001600160801b039092168252519081900360200190f35b610210610d6f565b610210610d93565b610344610db7565b610380610dcd565b6040805161ffff9092168252519081900360200190f35b61023c600480360360608110156103ad57600080fd5b6001600160a01b03823516916020810135918101906060810160408201356401000000008111156103dd57600080fd5b8201836020820111156103ef57600080fd5b8035906020019184602083028401116401000000008311171561041157600080fd5b509092509050610df1565b61023c6004803603604081101561043257600080fd5b5080356001600160a01b0316906020013563ffffffff16610e7c565b610344611089565b7f000000000000000000000000000000000000000000000000000000000000001281565b60015460ff166104c0576040805162461bcd60e51b815260206004820152600c60248201526b139bdd0819195d1858da195960a21b604482015290519081900360640190fd5b6104cc8484848461117a565b6104d7848485611244565b50505050565b7f0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561053657600080fd5b505afa15801561054a573d6000803e3d6000fd5b505050506040513d602081101561056057600080fd5b50516001600160a01b031633146105ab576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015290519081900360640190fd5b60015460ff16156105ee576040805162461bcd60e51b815260206004820152600860248201526711195d1858da195960c21b604482015290519081900360640190fd5b60007f0000000000000000000000002f7350cb5e434c2d177922110c7e314953b84afc6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561064957600080fd5b505afa15801561065d573d6000803e3d6000fd5b505050506040513d602081101561067357600080fd5b5051905061068142826113fa565b610693836001600160801b03166110ad565b6001805466ffffffffffffff92909216600160481b0266ffffffffffffff60481b19909216919091179081905563ffffffff808416600160281b9092041610610716576040805162461bcd60e51b815260206004820152601060248201526f496e76616c696420456e642054696d6560801b604482015290519081900360640190fd5b6001805464ffffffff00191661010063ffffffff85160217908190557f5208ab6d453e25ff339785d249c1622a65a099886cb31e91ba4bce4987d3316c9061076d90600160481b900466ffffffffffffff1661147c565b6040805191825263ffffffff851660208301528051918290030190a1505050565b7f0000000000000000000000002f7350cb5e434c2d177922110c7e314953b84afc81565b336001600160a01b037f0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f161461081f576040805162461bcd60e51b815260206004820152600d60248201526c13db9b1e48139bdd1a5bdb985b609a1b604482015290519081900360640190fd5b60015460ff161561086a576040805162461bcd60e51b815260206004820152601060248201526f105b1c9958591e4819195d1858da195960821b604482015290519081900360640190fd5b60007f0000000000000000000000002f7350cb5e434c2d177922110c7e314953b84afc6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108c557600080fd5b505afa1580156108d9573d6000803e3d6000fd5b505050506040513d60208110156108ef57600080fd5b505190506108fd42826113fa565b6001805460ff1916811766ffffffffffffff60481b191690819055610100900463ffffffff16421015610945576001805464ffffffff0019166101004263ffffffff16021790555b600154604080516000815261010090920463ffffffff16602083015280517f5208ab6d453e25ff339785d249c1622a65a099886cb31e91ba4bce4987d3316c9281900390910190a150565b60005481565b600154610100900463ffffffff1681565b336001600160a01b037f0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f1614610a14576040805162461bcd60e51b815260206004820152600d60248201526c13db9b1e48139bdd1a5bdb985b609a1b604482015290519081900360640190fd5b60015460ff1615610a57576040805162461bcd60e51b815260206004820152600860248201526711195d1858da195960c21b604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000b61ffff168461ffff1614610ac7576040805162461bcd60e51b815260206004820152601160248201527015dc9bdb99c818dd5c9c995b98de481a59607a1b604482015290519081900360640190fd5b610ad142826113fa565b610adc858484611244565b5050505050565b60015460ff1681565b600154600160281b900463ffffffff1681565b7f0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b5857600080fd5b505afa158015610b6c573d6000803e3d6000fd5b505050506040513d6020811015610b8257600080fd5b50516001600160a01b03163314610bcd576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015290519081900360640190fd5b6001600160a01b038216610c3657604051600090339083908381818185875af1925050503d8060008114610c1d576040519150601f19603f3d011682016040523d82523d6000602084013e610c22565b606091505b5050905080610c3057600080fd5b50610c41565b610c4182338361148a565b5050565b7f0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c9e57600080fd5b505afa158015610cb2573d6000803e3d6000fd5b505050506040513d6020811015610cc857600080fd5b50516001600160a01b03163314610d13576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015290519081900360640190fd5b80610d4f576040805162461bcd60e51b8152602060048201526007602482015266125b9d985b1a5960ca1b604482015290519081900360640190fd5b600055565b6002602052600090815260409020546001600160801b031681565b7f0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f81565b7f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f81565b600154600160801b90046001600160801b031681565b7f000000000000000000000000000000000000000000000000000000000000000b81565b60015460009060ff168015610e07575060005415155b610e47576040805162461bcd60e51b815260206004820152600c60248201526b139bdd0819195d1858da195960a21b604482015290519081900360640190fd5b610e538585858561117a565b610e738585600160109054906101000a90046001600160801b0316611506565b95945050505050565b60015460009060ff1615610ec2576040805162461bcd60e51b815260206004820152600860248201526711195d1858da195960c21b604482015290519081900360640190fd5b60015463ffffffff808416600160281b909204161115610f1e576040805162461bcd60e51b8152602060048201526012602482015271496e76616c696420626c6f636b2074696d6560701b604482015290519081900360640190fd5b60007f0000000000000000000000002f7350cb5e434c2d177922110c7e314953b84afc6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f7957600080fd5b505afa158015610f8d573d6000803e3d6000fd5b505050506040513d6020811015610fa357600080fd5b5051604080516370a0823160e01b81526001600160a01b03878116600483015291519293506000927f0000000000000000000000002f7350cb5e434c2d177922110c7e314953b84afc909216916370a0823191602480820192602092909190829003018186803b15801561101657600080fd5b505afa15801561102a573d6000803e3d6000fd5b505050506040513d602081101561104057600080fd5b50516001549091506000906110639063ffffffff80881691610100900416611592565b9050600061107182856115ac565b905061107e878483611506565b979650505050505050565b6001546000906110a890600160481b900466ffffffffffffff1661147c565b905090565b60008065ffffffffffff8311156110cd57602f6110c9846110dc565b0390505b82811c60081b1790505b919050565b6000816110e857600080fd5b600160801b82106110fb57608091821c91015b68010000000000000000821061111357604091821c91015b640100000000821061112757602091821c91015b62010000821061113957601091821c91015b610100821061114a57600891821c91015b6010821061115a57600491821c91015b6004821061116a57600291821c91015b600282106110d757600101919050565b6000848460405160200180836001600160a01b031660601b81526014018281526020019250505060405160208183030381529060405280519060200120905060006111fa84848080602002602001604051908101604052809392919081815260200183836020028082843760009201829052505492508691506116419050565b90508061123c576040805162461bcd60e51b815260206004820152600b60248201526a4e6f74496e4d65726b6c6560a81b604482015290519081900360640190fd5b505050505050565b60006112668484600160109054906101000a90046001600160801b0316611506565b6001549091506112a09061129b906305f5e10090611295908690600160801b90046001600160801b03166116ea565b90611711565b611730565b6001600160a01b038516600090815260026020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b039290921691909117905580156104d7577f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b031663a9059cbb85836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b15801561135c57600080fd5b505af192505050801561136d575060015b611376576104d7565b600061138061174a565b90508015610adc57846001600160a01b03167f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b03167fa282a314ffba449688a7c5eb4426bd8e1781944ce824ce34dfaea4691d08f146846040518082815260200191505060405180910390a35050505050565b600154610100900463ffffffff1661141157600080fd5b60015460009061142f9063ffffffff80861691610100900416611592565b905061143b81836115ac565b6001805463ffffffff4216600160281b0268ffffffff0000000000196001600160801b03948516600160801b02949092169390931716919091179055505050565b600881901c60ff9091161b90565b826001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156114e157600080fd5b505af11580156114f5573d6000803e3d6000fd5b50505050611501611785565b505050565b6001600160a01b03831660009081526002602052604081205461158a90670de0b6b3a7640000906112959060ff7f000000000000000000000000000000000000000000000000000000000000001216600a0a90611584906001600160801b039081169061157e906305f5e1009086908c908c166116ea565b906117f2565b906116ea565b949350505050565b60008183126115a157816115a3565b825b90505b92915050565b600154600090819063ffffffff808616600160281b909204161080156115d25750826000105b156116205760015463ffffffff600160281b909104811685031661161c846112956301da9c0081611601611089565b6001600160801b031661158487670de0b6b3a76400006116ea565b9150505b60015461158a9061129b90600160801b90046001600160801b031683611807565b600081815b85518110156116df57600086828151811061165d57fe5b602002602001015190508083116116a457828160405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092506116d6565b808360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b50600101611646565b509092149392505050565b6000826116f9575060006115a6565b8282028284828161170657fe5b04146115a357600080fd5b600080821161171f57600080fd5b81838161172857fe5b049392505050565b60006001600160801b0382111561174657600080fd5b5090565b6000611754611819565b3d801561176c57602081146117755760009250611780565b60019250611780565b60206000833e815192505b505090565b600061178f611819565b3d80156117a357602081146117ac57600080fd5b600192506117b7565b60206000833e815192505b5081610c41576040805162461bcd60e51b8152602060048201526005602482015264045524332360dc1b604482015290519081900360640190fd5b60008282111561180157600080fd5b50900390565b6000828201838110156115a357600080fd5b6040518060200160405280600190602082028036833750919291505056fea2646970667358221220a74639935b148d816e897ebe75f8648de6b80ed7bd5ef4f5bd1ebdddbd81bddb64736f6c63430007060033

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

0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066c92280

-----Decoded View---------------
Arg [0] : notional (address): 0x6e7058c91F85E0F6db4fc9da2CA41241f5e4263f
Arg [1] : currencyId (uint16): 11
Arg [2] : incentive_token (address): 0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f
Arg [3] : _emissionRatePerYear (uint128): 0
Arg [4] : _endTime (uint32): 1724457600

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000006e7058c91f85e0f6db4fc9da2ca41241f5e4263f
Arg [1] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [2] : 00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000066c92280


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.