// SPDX-License-Identifier: GPL-3.0-only pragma solidity >0.7.0; pragma experimental ABIEncoderV2; /// @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) enum TokenType {UnderlyingToken, cToken, cETH, Ether, NonMintable} /// @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 assetCashAmount, 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} /****** Calldata objects ******/ /// @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; } /// @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 cashGroup; // Used during currency liquidations if the account has liquidity tokens MarketParameters[] markets; } /// @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 int256 rateDecimals; // The exchange rate from base to ETH (if rate invert is required it is already done) int256 rate; // Amount of buffer to apply to the exchange rate for negative balances. int256 buffer; // Amount of haircut to apply to the exchange rate for positive balances int256 haircut; // Liquidation discount for this currency int256 liquidationDiscount; } /// @notice Internal object used to handle balance state during a transaction struct BalanceState { uint256 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; // The last supply amount when tokens were claimed uint256 lastClaimSupply; } /// @dev Asset rate used to convert between underlying cash and asset cash struct AssetRateParameters { // Address of the asset rate oracle address 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 { uint256 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 implied rate that we use to smooth the anchor rate between trades. uint256 lastImpliedRate; // This is the oracle rate used to value fCash and prevent flash loan attacks uint256 oracleRate; // This is the timestamp of the previous trade uint256 previousTradeTime; // Used to determine if the market has been updated bytes1 storageState; } /// @dev Simplified market object used during settlement struct SettlementMarket { bytes32 storageSlot; // 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; // Un parsed market data used for storage bytes32 data; } /// @dev Used during settling bitmap assets for calculating bitmap shifts struct SplitBitmap { bytes32 dayBits; bytes32 weekBits; bytes32 monthBits; bytes32 quarterBits; } /****** Storage objects ******/ /// @dev Token object in storage struct TokenStorage { // Address of the token address tokenAddress; // Transfer fees will change token deposit behavior bool hasTransferFee; TokenType tokenType; } /// @dev Exchange rate object as it is represented in storage, total storage is 25 bytes. struct ETHRateStorage { // Address of the rate oracle address 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 object as it is represented in storage, total storage is 21 bytes. struct AssetRateStorage { // Address of the rate oracle address rateOracle; // The decimal places of the underlying asset uint8 underlyingDecimalPlaces; } /// @dev Governance parameters for a cash group, total storage is 7 bytes + 9 bytes for liquidity token haircuts /// and 9 bytes for rate scalars, total of 25 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 minutes that the rate oracle will be averaged over uint8 rateOracleTimeWindowMin; // 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 Used in view methods to return account balances in a developer friendly manner struct AccountBalance { uint256 currencyId; int256 cashBalance; int256 nTokenBalance; uint256 lastClaimTime; uint256 lastClaimSupplyAmount; }