Native ERC1155 fCash transfers are a powerful tool that can be used to trade fCash OTC (over the counter) without impacting fCash markets.
The vast majority of fCash lending and borrowing will be done via Notional's fCash markets (on-chain AMM) but Notional also exposes ERC1155 transfers for fCash as a powerful tool to trade fCash OTC (over the counter). OTC trading can be used when fCash is idiosyncratic (i.e. temporarily illiquid due to no matching market maturity).
ERC1155 IDs
The ERC1155 standard is a "multi-token" standard that allows a single interface to transfer multiple tokens that are fungible inside a single contract. fCash is natively implemented as ERC1155 tokens inside the main Notional v2 Proxy contract. Each fCash token is uniquely identified by an ERC1155 id that is constructed as follows:
The native ERC1155 standard returns a uint256 value in balanceOf which is insufficient to express negative fCash balances. Notional's ERC1155 implementation will return 0 if an account has a negative fCash balance using balanceOf and will return the proper balance as an int256 when the non-ERC1155 standard signedBalanceOf is called.
Transfers
fCash can be transferred between two accounts using corresponding ids just like any other token. However, since fCash can also be negative there are some interesting properties that can be unlocked via transfers. If the from account does not have sufficient fCash to transfer to to they will incur a debt that must be collateralized on Notional. This unique property can be used to create potential OTC trades.
Example: Lending and Borrowing OTC at Idiosyncratic Maturity
In this example, the from account would like to sell 9 month (idiosyncratic) fCash to a market maker (to). The market maker will receive 9 month fCash and borrow at the liquid 12 month fCash AMM market, charge a spread, and transfer the remaining borrowed amount to the from account. The market maker's 12 month borrow is now collateralized by the 9 month fCash.
BatchBalanceWithTrades[] memory action =newBatchLend(1);action =new BalanceActionWithTrades[](1);action[0].actionType = DepositActionType.None;action[0].currencyId = currencyId;action[0].withdrawEntireCashBalance =true;action[0].redeemToUnderlying = toUnderlying;action[0].trades =newbytes32[](1);action[0].trades[0] =encodeBorrowTrade(3,// 1 year market100e8,// borrow 100 fCash0.05e9// revert if borrowed rate is above 5% annualized);// Encode the batch action as calldata, Notional will execute this trade// after exectuing a transfer between accounts.bytesmemory callData = abi.encodeWithSelector( NotionalProxy.batchBalanceAndTradeAction.selector, marketMakerAddress, action);// Some third party operator contract must execute this transaction and have// approval from both parties because te marketMakerAddress is executing// a borrow transaction. This third party operator must also implement// the ERC20 token transfer of borrowed assets from marketMakerAddress to // fromAddress.Notional.setApprovalForAll(fromAddress, operator);Notional.setApprovalForAll(marketMakerAddress, operator);// In this call, Notional will do the following:// - transfer fCash fromAddress to marketMakerAddress// - execute the borrowing on behalf of market maker encoded in callDataNotional.safeTransferFrom( fromAddress,// Transfer fCash from this address marketMakerAddress,// Market maker will borrowencodeAssetId(currencyId, maturity,1),// fCash ID100e8,// Send the 100e8 fDAI being purchased above callData // Execute the encoded trade on behalf of marketMakerAddress);
Example: Bi-Directional fCash Swap
Two accounts may also agree to trade fCash between each other using a single safeBatchTransferFrom. In this example, the from account will send 1 year fCash and receive 9 month fCash from the to account. This requires using a negative fCash balance in an element of the amounts array.
// Some third party operator must have approval to execute ERC1155 exchanges// in this case because the `to` account will be losing fCash in one of the// ids.Notional.setApprovalForAll(fromAddress, operator);Notional.setApprovalForAll(toAddress, operator);uint256[] memory amounts =newuint256[](2);amounts[0] =100e8// Send 9 month fCash amountamounts[1] =uint256(int256(-97.5e8)) // Receive 12 month fCash amount uint256[] memory ids =newuint256[](2);ids[0] =encodeAssetId(currencyId, nineMonthMaturity,1);ids[1] =encodeAssetId(currencyId, twelveMonthMaturity,1);Notional.safeBatchTransferFrom( fromAddress,// Send 9 month fCash, receive 12 month fCash toAddress,// Receive 9 month fCash, send 12 month fCash ids, amounts,"");