// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.7.6; pragma abicoder v2; import "../../interfaces/chainlink/AggregatorV2V3Interface.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 assetCashAmount, 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 { uint256 currencyId; int256 netCashChange; } /// @notice Internal object that represents a token struct Token { address tokenAddress; bool hasTransferFee; int256 decimals; TokenType tokenType; uint256 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 localAssetAvailable; // 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 nTokenHaircutAssetValue; // 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 AssetRateParameters localAssetRate; // 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; // Net asset transfers into or out of the account int256 netAssetTransferInternalPrecision; // 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; } /// @dev Asset rate used to convert between underlying cash and asset cash struct 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; AssetRateParameters assetRate; bytes32 data; } /// @dev A portfolio asset when loaded in memory struct PortfolioAsset { // Asset currency id uint256 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 totalAssetCash; // 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; // Upper limit on how much of this token the contract can hold at any time uint72 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; // Total fees per trade, specified in BPS uint8 totalFeeBPS; // Share of the fees given to the protocol, denominated in percentage uint8 reserveFeeShare; // Debt buffer specified in 5 BPS increments uint8 debtBuffer5BPS; // fCash haircut specified in 5 BPS increments uint8 fCashHaircut5BPS; // If an account has a negative cash balance, it can be settled by incurring debt at the 3 month market. This // is the basis points for the penalty rate that will be added the current 3 month oracle rate. uint8 settlementPenaltyRate5BPS; // If an account has fCash that is being liquidated, this is the discount that the liquidator can purchase it for uint8 liquidationfCashHaircut5BPS; // If an account has fCash that is being liquidated, this is the discount that the liquidator can purchase it for uint8 liquidationDebtBuffer5BPS; // Liquidity token haircut applied to cash claims, specified as a percentage between 0 and 100 uint8[] liquidityTokenHaircuts; // Rate scalar used to determine the slippage of the market uint8[] rateScalars; } /// @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; } /// @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 bytes5 nTokenParameters; // Reserved bytes for future usage bytes15 _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 totalAssetCash; // 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 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 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; // 80 bytes left } struct VaultBorrowCapacityStorage { // Total fCash across all maturities that caps the borrow capacity uint80 maxBorrowCapacity; // Current usage of that total borrow capacity uint80 totalUsedBorrowCapacity; } struct VaultSecondaryBorrowStorage { // fCash borrowed for a specific maturity on a secondary currency uint80 totalfCashBorrowed; // Used for accounting how much secondary borrow a single account owes as the fCashBorrowed // increases or decreases uint80 totalAccountDebtShares; // The total secondary fCash borrowed converted to the primary borrow currency (underlying) // snapshot prior to settlement. This is used to offset account value on settlement. Once this // value is set, accounts can no longer borrow or repay on the secondary borrow currency uint80 totalfCashBorrowedInPrimarySnapshot; // Set to true once when the snapshot is set bool hasSnapshotBeenSet; } 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; AssetRateParameters assetRate; int256 maxRequiredAccountCollateralRatio; } /// @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. This value must equal the total fCash borrowed by all accounts // in the vault. uint80 totalfCash; // The total amount of asset cash in the pool held as prepayment for fCash uint80 totalAssetCash; // Total vault shares in this maturity uint80 totalVaultShares; // Set to true if a vault has been fully settled and the cash can be pulled. Matured // accounts must wait for this flag to be set before they can proceed to exit after // maturity bool isSettled; // NOTE: 8 bits left // ----- This breaks into a new storage slot ------- // TODO: potentially make total strategy tokens bigger... // The total amount of strategy tokens held in the pool uint80 totalStrategyTokens; // Valuation of a strategy token at settlement int80 settlementStrategyTokenValue; // NOTE: 96 bits left } /// @notice Represents the remaining assets in a vault post settlement struct VaultSettledAssetsStorage { // Remaining strategy tokens that have not been withdrawn uint80 remainingStrategyTokens; // Remaining asset cash that has not been withdrawn int80 remainingAssetCash; } struct VaultState { uint256 maturity; int256 totalfCash; bool isSettled; uint256 totalVaultShares; uint256 totalAssetCash; uint256 totalStrategyTokens; int256 settlementStrategyTokenValue; } /// @notice Represents an account's position within an individual vault struct VaultAccountStorage { // The amount of fCash the account has borrowed from Notional. Stored as a uint but on the stack it // is represented as a negative number. uint80 fCash; // Vault shares that the account holds uint80 vaultShares; // Maturity when the vault shares and fCash will mature uint40 maturity; // Last block when a vault entered, 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. uint32 lastEntryBlockHeight; } 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 shares for the first secondary currency uint80 accountDebtSharesOne; // Account debt shares for the second secondary currency uint80 accountDebtSharesTwo; } struct VaultAccount { int256 fCash; 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 lastEntryBlockHeight; }