CASH_RECEIVER) or obligated to pay (
CASH_PAYER) at its designated maturity. For example, if an account holds +100 fCash tokens for a maturity at timestamp 100, it is entitled to 100 Dai at any time greater than or equal to timestamp 100. Similarly, -100 fCash tokens for the same maturity means that the account is obligated to pay 100 Dai at timestamp 100. A detailed description of lending and borrowing mechanics will follow.
CASH_RECEIVER) is freely transferrable but the obligation to pay (
CASH_PAYER) is not.
CASH_RECEIVER) or negative (
CASH_PAYER), current cash is represented as a signed integer (i.e. positive or negative).
G_MATURITY_LENGTHdefines how long each periodic maturity will last in seconds.
G_NUM_MATURITIESdefines how many of these maturities will be traded in the future. For example, if
G_MATURITY_LENGTH = 1000and
G_NUM_MATURITIES = 4and we are starting at time 0, there will be maturities at timestamps 1000, 2000, 3000, 4000. Each one of these maturities will have a pool of fCash tokens that can be bought and sold.
rateScalarare governance parameters that determine the offset from zero and the slope of the curve, respectively. The
proportionis determined by liquidity providers and trading in the market in general. Like Uniswap, the first liquidity provider will be able to set this proportion and therefore impact the initial rate. Importantly, however, the ratio of current cash and fCash the liquidity provider adds does not determine the interest rate in isolation (like it would in Uniswap), it is one factor in combination with the two governance parameters.
rateScalarvalue of 100, this trade would move the exchange rate 0.02%. That equates to a 0.24% move in the annualized interest rate -- a much more reasonable slippage.
impliedPeriodRate = (exchangeRate - 1) * MATURITY_LENGTH / timeToMaturity)
takefCashfunction allows users to deposit cash (i.e. Dai) to the market in exchange for the right to receive a cash flow at maturity. This is the equivalent of lending; the user is depositing cash for the right to receive a (hopefully larger) cash flow at maturity. From an economic standpoint, the user would simply not deposit cash unless they were entitled to a greater amount of fCash at maturity; no one would trade 100 Dai today for 95 Dai in the future. If the exchange rate were to fall to that level, arbitrageurs could easily obtain risk-free profits by moving it back into line with the market's expectation for interest rates over the given period. The
getExchangeRatefunction is described in detail in Appendix A.
takeCurrentCashfunction allows users to deposit a fCash obligation in order to receive cash. This is the equivalent of borrowing; the user is committing to a future obligation in exchange for an amount of Dai that they can withdraw from the contract and spend as they wish. This obligation will be collateralized by ETH,
LIQUIDITY_TOKEN. See the Portfolio section for more details on this. The
getExchangeRatefunction is described in detail in Appendix A.
takefCash) are calculated when the trade is made. This means, in effect, the interest rate for the user is fixed from that point on. A lender will not have to deposit any more Dai for the cash flow that they are promised; the borrower will not have to pay more fCash for the Dai they received.
totalfCashhave changed after the previous trade, the next lender will receive a different fixed rate.
removeLiquidityfunctions. When a liquidity provider adds liquidity, they deposit Dai and fCash at the prevailing exchange rate to both sides of the market. The provider submits the amount of fCash to add and the corresponding amount of Dai is calculated using the current exchange rate. Liquidity tokens are minted to account for the provider's contribution. Since the liquidity provider is depositing fCash, we create a
CASH_PAYERtoken to represent the obligation a liquidity provider has to provide that fCash when the market matures. The net present value of the
LIQUIDITY_TOKENwill partially offset this obligation.
CASH_RECEIVERhere will offset the
CASH_PAYERthat was added to the liquidity provider's portfolio when they deposited the tokens. The pseudocode is below:
G_LIQUIDITY_FEE) on every transaction. The advantage of this design is that liquidity providers can passively provide liquidity and earn transaction fees in the market.
LIQUIDITY_TOKENpositions have a claim on Dai, if there is insufficient Dai and ETH balances to settle a negative cash position, liquidity tokens will be withdrawn from the markets for their dai portion in order to settle the cash position. See portfolio assets for a full explanation.
LIQUIDITY_TOKENbalances. The reason for storing this in an array as opposed to mappings is so that the contract can iterate over a portfolio and calculate the net present value of all the assets that the account holds. We do this in order to calculate free collateral. It is important to note that each asset in the portfolio contains some amount of risk and therefore we apply a [currency buffer](#currency buffer-(collateralization-ratio)) to the value of each asset.
CASH_RECEIVERpositions. If an account has an obligation of 100 fCash in 1 year (
CASH_PAYER), but then buys the right to receive 50 fCash (
CASH_RECEIVER) at the same maturity, its net position is now a
CASH_PAYERof 50 fCash in 1 year. The portfolio construction ensures that there is always only one entry per maturity that represents the net position of the account no matter how many trades they have made in that maturity.
CASH_RECEIVERtokens in the liquidity pool of a specified maturity. As trades occur, the claim the liquidity tokens have will shift between current cash and the cash receivers. Since
CASH_RECEIVERtokens hold no value in the free collateral calculation, the amount of current cash an account has available to collateralize other obligations will shift as trades occur.
G_LIQUIDITY_HAIRCUTparameter. The calculation is as follows:
CASH_RECEIVERrepresents cash an account is scheduled to receive at maturity. Any time before maturity,
CASH_RECEIVERtokens may be sold for current cash if there is sufficient liquidity in the relevant cash market. Since there is no guarantee that this liquidity will be available if a
CASH_RECEIVERtoken must be liquidated to pay off obligations, we apply a haircut to the value of these tokens. We haircut it by 50% on an annualied basis. Therefore 100 Dai
CASH_RECEIVERtokens maturing in 1 year will be valued at 50 Dai. 100 Dai
CASH_RECEIVERtokens maturing in 6 months will be valued at 75 Dai. We apply a max haircut value to ensure that strange behaviors do not occur as these assets get close to maturity. The haircut applied follows the formula:
CASH_PAYERtokens represent obligations and are the only source of negative collateral.
CASH_PAYERtokens convert to negative cash balances as maturity which will continue to be a source of negative collateral.
LIQUIDITY_TOKENassets are potential sources of positive collateral within an account's portfolio. Currently, Notional only uses the liquidity tokens' claim on Dai as an asset. In the event of liquidation, these tokens would be removed from the market and the account would be credited with its claim on both Dai and fDai.
daiClaimin the liquidity token. Therefore, only the haircut portion of this
daiClaimis actually available to recollateralize the account. For example, in the cash ladder section we describe an account that has a 475 post haircut Dai claim. The difference between this and the actual 500 Dai claim (25 Dai) is what is available to recollateralize the account.
CASH_RECEIVERassets as a source of positive collateral. We do not allow liquidation of until this condition is met -- meaning there are no liquidity tokens or positive cash balances in the portfolio. We do this because liquidating fCash is risky on multiple fronts. First we must sell the entire balance of the fCash asset into the market, we cannot calculate a portion of the
CASH_RECEIVERto sell (see Appendix A: Calculating Current Cash Requirement). Secondly, it is unclear if the market will have sufficient liquidity to purchase an arbitrary
CASH_RECEIVERasset. When market proportions reach 90% fCash the calculations will start to overflow and prevent trading. Finally, if this is the case then we allow the liquidator to purchase the fCash asset at a severe discount (see: Cash Receiver Value)
CASH_RECEIVERassets will be liquidated, we first attempt to sell them into their respective market. If that fails then we allow the liquidator to purchase the assets.
rateScalaras the curve approaches maturity:
tradeExchangeRatesuch that the new implied rate matches the last implied rate the market traded at. The proof is as follows:
LIQUIDITY_TOKENs may exist in any currency. Because these are a source of positive free collateral we may have to liquidate them in order to recapitalize an account. Doing so is non trivial and so the algorithm will be described here.
CASH_PAYERmay require 120 Dai worth of other assets), by repaying the 100 Dai debt the account will have a net 20 Dai benefit in its free collateral position.
netCurrencyAvailable = cashBalance + postHaircutCashClaim - requirement
LIQUIDITY_TOKEN_HAIRCUTimplies that accounts may become undercollateralized but have a source of positive cash in their liquidity token cash claims. Note that this situation can arise when providing liquidity because it is done on leverage; when the liquidity provider deposits cash into a market they incur a debt equal to their pre haircut fCash claim.
LIQUIDITY_TOKEN_REPO_INCENTIVE. Note that only the difference between the cash claim and the post haircut cash claim is available to recollateralize the account. The post haircut cash claim has already been accounted for in the free collateral calculation. The formula is as follows:
cashClaim - cashClaim * liquidityTokenHaircut = localCurrencyRequired * (1 + incentive)
cashClaim = localCurrencyRequired * (1 + incentive) / (1 - liquidityTokenHaircut)
localCurrencyRequired * incentiveto the liquidator, this can be calculated as follows:
incentivePayment = cashClaim * (1 - liquidityTokenHaircut) - localCurrencyRequired
netCurrencyAvailable' = netCurrencyAvailable + cashClaim * (1 - liquidityTokenHaircut) - incentivePayment
cashClaim = 10 Dai * (1.01) / 0.1 = 101 Dai
incentivePayment = 101 Dai * (0.1) - 10 Dai = 0.1 Dai
netCurrencyAvailable' = -10 + 101 * (0.1) - 0.1 Dai = 0 Dai
LIQUIDITY_TOKENin this scenario also holds a claim to fDai which may potentially recollateralize the account if the
LIQUIDITY_TOKENare in the same maturity. This is because the fDai will directly offset the negative balance of the
CASH_PAYER. For simplicity, we do not account for this during liquidation at this time.
collateralToSell = localCurrencyRequired * exchangeRate[local][collateral] * liquidationDiscount
amountToRaise: the amount of cash claims that must be removed from liquidity tokens and given to the liquidator
balanceToTransfer: the portion of the liquidated account's cash balance that will be given to the liquidator
creditToAccount: the amount to credit back to the liquidated account from the
CASH_RECEIVERassets in a collateral currency during liquidation. Since we will not trade
CASH_RECEIVERduring liquidation (only during liquidate fCash) we must adjust the netCollateralAvailable figure accordingly. In this case we want to ensure that positive value from fCash is used to net off against negative current cash balances.
CASH_RECEIVERat the same maturity offset each other, creation and trading of these assets should not be limited to on chain markets. We allow accounts to agree to create offsetting fCash pairs off chain and submit them to Notional for settlement. Accounts holding
CASH_PAYERassets must hold sufficient collateral for their debts.
CASH_RECEIVERassets that have corresponding on chain cash markets will contribute positive collateral to a portfolio.
CASH_RECEIVERassets that are idiosyncratic (i.e do not have a maturity that corresponds to a market on chain), have no positive collateral value. This restriction may be lifted in the future if there are liquid markets for purchasing these types of assets during liquidation.