mirror of
https://github.com/Instadapp/dsa-connectors.git
synced 2024-07-29 22:37:00 +00:00
814 lines
26 KiB
Solidity
814 lines
26 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.7.6;
|
|
pragma abicoder v2;
|
|
|
|
/**
|
|
* @title Notional
|
|
* @dev Fixed Rate Lending and Borrowing
|
|
*/
|
|
|
|
import { Helpers } from "./helpers.sol";
|
|
import { Events } from "./events.sol";
|
|
import { DepositActionType, BalanceActionWithTrades, BalanceAction } from "./interface.sol";
|
|
import { TokenInterface } from "../../common/interfaces.sol";
|
|
|
|
abstract contract NotionalResolver is Events, Helpers {
|
|
/**
|
|
* @notice Deposit collateral into Notional, this should only be used for reducing risk of
|
|
* liquidation.
|
|
* @dev Deposits into Notional are not earning fixed rates, they are earning the cToken
|
|
* lending rate. In order to lend at fixed rates use `depositAndLend`
|
|
* @param currencyId notional defined currency id to deposit
|
|
* @param useUnderlying if true, will accept a deposit in the underlying currency (i.e DAI), if false
|
|
* will use the asset currency (i.e. cDAI)
|
|
* @param depositAmount amount of tokens to deposit
|
|
* @param getId id of depositAmount
|
|
* @param setId id to set the value of notional cash deposit increase (denominated in asset cash, i.e. cDAI)
|
|
*/
|
|
function depositCollateral(
|
|
uint16 currencyId,
|
|
bool useUnderlying,
|
|
uint256 depositAmount,
|
|
uint256 getId,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
depositAmount = getDepositAmountAndSetApproval(
|
|
getId,
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount
|
|
);
|
|
|
|
uint256 assetCashDeposited;
|
|
if (useUnderlying && currencyId == ETH_CURRENCY_ID) {
|
|
assetCashDeposited = notional.depositUnderlyingToken{
|
|
value: depositAmount
|
|
}(address(this), currencyId, depositAmount);
|
|
} else if (useUnderlying) {
|
|
assetCashDeposited = notional.depositUnderlyingToken(
|
|
address(this),
|
|
currencyId,
|
|
depositAmount
|
|
);
|
|
} else {
|
|
assetCashDeposited = notional.depositAssetToken(
|
|
address(this),
|
|
currencyId,
|
|
depositAmount
|
|
);
|
|
}
|
|
|
|
setUint(setId, assetCashDeposited);
|
|
|
|
_eventName = "LogDepositCollateral(address,uint16,bool,uint256,uint256)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount,
|
|
assetCashDeposited
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Withdraw collateral from Notional
|
|
* @dev This spell allows users to withdraw collateral from Notional
|
|
* @param currencyId notional defined currency id to withdraw
|
|
* @param redeemToUnderlying if true, will redeem the amount withdrawn to the underlying currency (i.e. DAI),
|
|
* if false, will simply withdraw the asset token (i.e. cDAI)
|
|
* @param withdrawAmount amount of tokens to withdraw, denominated in asset tokens (i.e. cDAI)
|
|
* @param getId id of withdraw amount
|
|
* @param setId id to set the value of amount withdrawn, if redeemToUnderlying this amount will be in underlying
|
|
* (i.e. DAI), if not redeemToUnderlying this amount will be asset tokens (i.e. cDAI)
|
|
*/
|
|
function withdrawCollateral(
|
|
uint16 currencyId,
|
|
bool redeemToUnderlying,
|
|
uint256 withdrawAmount,
|
|
uint256 getId,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
withdrawAmount = getUint(getId, withdrawAmount);
|
|
uint88 amountInternalPrecision = withdrawAmount == type(uint256).max
|
|
? toUint88(getCashOrNTokenBalance(currencyId, false))
|
|
: toUint88(convertToInternal(currencyId, withdrawAmount));
|
|
|
|
uint256 amountWithdrawn = notional.withdraw(
|
|
currencyId,
|
|
amountInternalPrecision,
|
|
redeemToUnderlying
|
|
);
|
|
// Sets the amount of tokens withdrawn to address(this), Notional returns this value
|
|
// in the native precision of the token that was withdrawn
|
|
setUint(setId, amountWithdrawn);
|
|
|
|
_eventName = "LogWithdrawCollateral(address,uint16,bool,uint256)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
redeemToUnderlying,
|
|
amountWithdrawn
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Claims NOTE tokens and transfers to the address
|
|
* @dev This spell allows users to claim nToken incentives
|
|
* @param setId the id to set the balance of NOTE tokens claimed
|
|
*/
|
|
function claimNOTE(uint256 setId)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
uint256 notesClaimed = notional.nTokenClaimIncentives();
|
|
setUint(setId, notesClaimed);
|
|
|
|
_eventName = "LogClaimNOTE(address,uint256)";
|
|
_eventParam = abi.encode(address(this), notesClaimed);
|
|
}
|
|
|
|
/**
|
|
* @notice Redeem nTokens allowing for accepting of fCash residuals
|
|
* @dev This spell allows users to redeem nTokens even when there are fCash residuals that
|
|
* cannot be sold when markets are at extremely high utilization
|
|
* @param currencyId notional defined currency id of nToken
|
|
* @param sellTokenAssets set to false to accept fCash residuals into portfolio, set to true will
|
|
* sell fCash residuals back to cash
|
|
* @param tokensToRedeem amount of nTokens to redeem
|
|
* @param getId id of amount of tokens to redeem
|
|
* @param setId id to set amount of asset cash from redeem
|
|
*/
|
|
function redeemNTokenRaw(
|
|
uint16 currencyId,
|
|
bool sellTokenAssets,
|
|
uint96 tokensToRedeem,
|
|
bool acceptResidualAssets,
|
|
uint256 getId,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
tokensToRedeem = getNTokenRedeemAmount(
|
|
currencyId,
|
|
tokensToRedeem,
|
|
getId
|
|
);
|
|
|
|
int256 _assetCashChange = notional.nTokenRedeem(
|
|
address(this),
|
|
currencyId,
|
|
tokensToRedeem,
|
|
sellTokenAssets,
|
|
acceptResidualAssets
|
|
);
|
|
|
|
// Floor asset cash change at zero in order to properly set the uint. If the asset cash change is negative
|
|
// (this will almost certainly never happen), then no withdraw is possible.
|
|
uint256 assetCashChange = _assetCashChange > 0
|
|
? uint256(_assetCashChange)
|
|
: 0;
|
|
|
|
setUint(setId, assetCashChange);
|
|
|
|
_eventName = "LogRedeemNTokenRaw(address,uint16,bool,uint96,int256)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
sellTokenAssets,
|
|
tokensToRedeem,
|
|
assetCashChange
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Redeems nTokens to cash and withdraws the resulting cash
|
|
* @dev Also possible to use redeemNTokenRaw and withdrawCollateral to achieve the same
|
|
* result but this is more gas efficient, it does it in one call to Notional
|
|
* @param currencyId notional defined currency id of nToken
|
|
* @param tokensToRedeem amount of nTokens to redeem
|
|
* @param amountToWithdraw amount of asset cash to withdraw, if set to uint(-1) then will withdraw the
|
|
* entire cash balance in notional
|
|
* @param redeemToUnderlying if true, will redeem the asset cash withdrawn to underlying tokens
|
|
* @param getId id of amount of tokens to redeem
|
|
* @param setId id to set amount of asset cash or underlying tokens withdrawn
|
|
*/
|
|
function redeemNTokenAndWithdraw(
|
|
uint16 currencyId,
|
|
uint96 tokensToRedeem,
|
|
uint256 amountToWithdraw,
|
|
bool redeemToUnderlying,
|
|
uint256 getId,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
tokensToRedeem = getNTokenRedeemAmount(
|
|
currencyId,
|
|
tokensToRedeem,
|
|
getId
|
|
);
|
|
|
|
BalanceAction[] memory action = new BalanceAction[](1);
|
|
action[0].actionType = DepositActionType.RedeemNToken;
|
|
action[0].currencyId = currencyId;
|
|
action[0].depositActionAmount = tokensToRedeem;
|
|
action[0].redeemToUnderlying = redeemToUnderlying;
|
|
if (amountToWithdraw == type(uint256).max) {
|
|
// This setting will override the withdrawAmountInternalPrecision
|
|
action[0].withdrawEntireCashBalance = true;
|
|
} else {
|
|
action[0].withdrawAmountInternalPrecision = amountToWithdraw;
|
|
}
|
|
|
|
executeActionWithBalanceChange(
|
|
action,
|
|
0,
|
|
currencyId,
|
|
redeemToUnderlying,
|
|
setId
|
|
);
|
|
|
|
_eventName = "LogRedeemNTokenWithdraw(address,uint16,uint96,uint256,bool)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
tokensToRedeem,
|
|
amountToWithdraw,
|
|
redeemToUnderlying
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Redeems nTokens and uses the cash to repay a borrow.
|
|
* @dev When specifying fCashAmount be sure to calculate it such that the account
|
|
* has enough cash after redeeming nTokens to pay down the debt. This can be done
|
|
* off-chain using the Notional SDK.
|
|
* @param currencyId notional defined currency id of nToken
|
|
* @param tokensToRedeem amount of nTokens to redeem
|
|
* @param marketIndex the market index that references where the account will lend
|
|
* @param fCashAmount amount of fCash to lend into the market (this has the effect or repaying
|
|
* the borrowed cash at current market rates), the corresponding amount of cash will be taken
|
|
* from the account after redeeming nTokens.
|
|
* @param minLendRate minimum rate where the user will lend, if the rate is lower will revert
|
|
* @param getId id of amount of tokens to redeem
|
|
*/
|
|
function redeemNTokenAndDeleverage(
|
|
uint16 currencyId,
|
|
uint96 tokensToRedeem,
|
|
uint8 marketIndex,
|
|
uint88 fCashAmount,
|
|
uint32 minLendRate,
|
|
uint256 getId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
tokensToRedeem = getNTokenRedeemAmount(
|
|
currencyId,
|
|
tokensToRedeem,
|
|
getId
|
|
);
|
|
|
|
BalanceActionWithTrades[] memory action = new BalanceActionWithTrades[](
|
|
1
|
|
);
|
|
action[0].actionType = DepositActionType.RedeemNToken;
|
|
action[0].currencyId = currencyId;
|
|
action[0].depositActionAmount = tokensToRedeem;
|
|
// Withdraw amount, withdraw cash balance and redeemToUnderlying are all 0 or false
|
|
|
|
bytes32[] memory trades = new bytes32[](1);
|
|
trades[0] = encodeLendTrade(marketIndex, fCashAmount, minLendRate);
|
|
action[0].trades = trades;
|
|
|
|
notional.batchBalanceAndTradeAction(address(this), action);
|
|
|
|
_eventName = "LogRedeemNTokenAndDeleverage(address,uint16,uint96,uint8,uint88)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
tokensToRedeem,
|
|
marketIndex,
|
|
fCashAmount
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Deposit asset or underlying tokens and mint nTokens in a single transaction
|
|
* @dev This spell allows users to deposit and mint nTokens (providing liquidity)
|
|
* @param currencyId notional defined currency id to deposit
|
|
* @param depositAmount amount of tokens to deposit
|
|
* @param useUnderlying if true, will accept a deposit in the underlying currency (i.e DAI), if false
|
|
* will use the asset currency (i.e. cDAI)
|
|
* @param getId id of depositAmount
|
|
* @param setId id to set the value of nToken balance change
|
|
*/
|
|
function depositAndMintNToken(
|
|
uint16 currencyId,
|
|
uint256 depositAmount,
|
|
bool useUnderlying,
|
|
uint256 getId,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
depositAmount = getDepositAmountAndSetApproval(
|
|
getId,
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount
|
|
);
|
|
|
|
BalanceAction[] memory action = new BalanceAction[](1);
|
|
action[0].actionType = useUnderlying
|
|
? DepositActionType.DepositUnderlyingAndMintNToken
|
|
: DepositActionType.DepositAssetAndMintNToken;
|
|
action[0].currencyId = currencyId;
|
|
action[0].depositActionAmount = depositAmount;
|
|
// withdraw amount, withdraw cash and redeem to underlying are all 0 and false
|
|
|
|
uint256 nTokenBefore = getCashOrNTokenBalance(currencyId, true);
|
|
uint256 msgValue = getMsgValue(
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount
|
|
);
|
|
|
|
notional.batchBalanceAction{ value: msgValue }(address(this), action);
|
|
|
|
uint256 nTokenBalanceChange = sub(
|
|
getCashOrNTokenBalance(currencyId, true),
|
|
nTokenBefore
|
|
);
|
|
|
|
if (setId != 0) {
|
|
// Set the amount of nTokens minted
|
|
setUint(setId, uint256(nTokenBalanceChange));
|
|
}
|
|
|
|
_eventName = "LogDepositAndMintNToken(address,uint16,bool,uint256,int256)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount,
|
|
nTokenBalanceChange
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Uses existing Notional cash balance (deposits in Notional held as cTokens) and uses them to mint
|
|
* nTokens.
|
|
* @dev This spell allows users to mint nTokens (providing liquidity) from existing cash balance.
|
|
* @param currencyId notional defined currency id of the cash balance
|
|
* @param cashBalanceToMint amount of account's cash balance to convert to nTokens
|
|
* @param getId id of cash balance
|
|
* @param setId id to set the value of nToken increase
|
|
*/
|
|
function mintNTokenFromCash(
|
|
uint16 currencyId,
|
|
uint256 cashBalanceToMint,
|
|
uint256 getId,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
cashBalanceToMint = getUint(getId, cashBalanceToMint);
|
|
if (cashBalanceToMint == type(uint256).max)
|
|
cashBalanceToMint = getCashOrNTokenBalance(currencyId, false);
|
|
|
|
BalanceAction[] memory action = new BalanceAction[](1);
|
|
action[0].actionType = DepositActionType.ConvertCashToNToken;
|
|
action[0].currencyId = currencyId;
|
|
action[0].depositActionAmount = cashBalanceToMint;
|
|
// NOTE: withdraw amount, withdraw cash and redeem to underlying are all 0 and false
|
|
|
|
uint256 nTokenBefore = getCashOrNTokenBalance(currencyId, true);
|
|
|
|
notional.batchBalanceAction(address(this), action);
|
|
|
|
uint256 nTokenBalanceChange = sub(
|
|
getCashOrNTokenBalance(currencyId, true),
|
|
nTokenBefore
|
|
);
|
|
|
|
if (setId != 0) {
|
|
// Set the amount of nTokens minted
|
|
setUint(setId, uint256(nTokenBalanceChange));
|
|
}
|
|
|
|
_eventName = "LogMintNTokenFromCash(address,uint16,uint256,int256)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
cashBalanceToMint,
|
|
nTokenBalanceChange
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Deposits some amount of tokens and lends them in the specified market. This method can also be used to repay a
|
|
* borrow early by specifying the corresponding market index of an existing borrow.
|
|
* @dev Setting the fCash amount and minLendRate are best calculated using the Notional SDK off chain. They can
|
|
* be calculated on chain but there is a significant gas cost to doing so. If there is insufficient depositAmount for the
|
|
* fCashAmount specified Notional will revert. In most cases there will be some dust amount of cash left after lending and
|
|
* this method will withdraw that dust back to the account.
|
|
* @param currencyId notional defined currency id to lend
|
|
* @param depositAmount amount of cash to deposit to lend
|
|
* @param useUnderlying if true, will accept a deposit in the underlying currency (i.e DAI), if false
|
|
* will use the asset currency (i.e. cDAI)
|
|
* @param marketIndex the market index to lend to. This is a number from 1 to 7 which corresponds to the tenor
|
|
* of the fCash asset to lend. Tenors are described here: https://docs.notional.finance/notional-v2/quarterly-rolls/tenors
|
|
* @param fCashAmount amount of fCash for the account to receive, this is equal to how much the account will receive
|
|
* at maturity (principal plus interest).
|
|
* @param minLendRate the minimum interest rate that the account is willing to lend at, if set to zero the account will accept
|
|
* any lending rate
|
|
* @param getId returns the deposit amount
|
|
*/
|
|
function depositAndLend(
|
|
uint16 currencyId,
|
|
uint256 depositAmount,
|
|
bool useUnderlying,
|
|
uint8 marketIndex,
|
|
uint88 fCashAmount,
|
|
uint32 minLendRate,
|
|
uint256 getId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
depositAmount = getDepositAmountAndSetApproval(
|
|
getId,
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount
|
|
);
|
|
|
|
BalanceActionWithTrades[] memory action = new BalanceActionWithTrades[](
|
|
1
|
|
);
|
|
action[0].actionType = useUnderlying
|
|
? DepositActionType.DepositUnderlying
|
|
: DepositActionType.DepositAsset;
|
|
action[0].currencyId = currencyId;
|
|
action[0].depositActionAmount = depositAmount;
|
|
// Withdraw any residual cash from lending back to the token that was used
|
|
action[0].withdrawEntireCashBalance = true;
|
|
action[0].redeemToUnderlying = useUnderlying;
|
|
|
|
bytes32[] memory trades = new bytes32[](1);
|
|
trades[0] = encodeLendTrade(marketIndex, fCashAmount, minLendRate);
|
|
action[0].trades = trades;
|
|
|
|
uint256 msgValue = getMsgValue(
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount
|
|
);
|
|
notional.batchBalanceAndTradeAction{ value: msgValue }(
|
|
address(this),
|
|
action
|
|
);
|
|
|
|
_eventName = "LogDepositAndLend(address,uint16,bool,uint256,uint8,uint88,uint32)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
useUnderlying,
|
|
depositAmount,
|
|
marketIndex,
|
|
fCashAmount,
|
|
minLendRate
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Deposits some amount of tokens as collateral and borrows. This can be achieved by combining multiple spells but this
|
|
* method is more gas efficient by only making a single call to Notional.
|
|
* @dev Setting the fCash amount and maxBorrowRate are best calculated using the Notional SDK off chain. The amount of fCash
|
|
* when borrowing is more forgiving compared to lending since generally accounts will over collateralize and dust amounts are
|
|
* less likely to cause reverts. The Notional SDK will also provide calculations to tell the user what their LTV is for a given
|
|
* borrowing action.
|
|
* @param depositCurrencyId notional defined currency id of the collateral to deposit
|
|
* @param depositAction one of the following values which will define how the collateral is deposited:
|
|
* - None: no collateral will be deposited
|
|
* - DepositAsset: deposit amount will be specified in asset tokens (i.e. cTokens)
|
|
* - DepositUnderlying: deposit amount will be specified in underlying tokens (i.e. DAI)
|
|
* - DepositAssetAndMintNToken: deposit amount will be converted to nTokens
|
|
* - DepositUnderlyingAndMintNToken: deposit amount will be converted to nTokens
|
|
*
|
|
* Technically these two deposit types can be used, but there is not a clear reason why they would be used in combination
|
|
* with borrowing:
|
|
* - RedeemNToken
|
|
* - ConvertCashToNToken
|
|
*
|
|
* @param depositAmount amount of cash to deposit as collateral
|
|
* @param borrowCurrencyId id of the currency to borrow
|
|
* @param marketIndex the market index to borrow from. This is a number from 1 to 7 which corresponds to the tenor
|
|
* of the fCash asset to borrow. Tenors are described here: https://docs.notional.finance/notional-v2/quarterly-rolls/tenors
|
|
* @param fCashAmount amount of fCash for the account to borrow, this is equal to how much the account must pay
|
|
* at maturity (principal plus interest).
|
|
* @param maxBorrowRate the maximum interest rate that the account is willing to borrow at, if set to zero the account will accept
|
|
* any borrowing rate
|
|
* @param redeemToUnderlying if true, redeems the borrowed balance from cTokens down to the underlying token before transferring
|
|
* to the account
|
|
* @param getId returns the collateral deposit amount
|
|
* @param setId sets the amount that the account borrowed (i.e. how much of borrowCurrencyId it has received)
|
|
*/
|
|
function depositCollateralBorrowAndWithdraw(
|
|
uint16 depositCurrencyId,
|
|
DepositActionType depositAction,
|
|
uint256 depositAmount,
|
|
uint16 borrowCurrencyId,
|
|
uint8 marketIndex,
|
|
uint88 fCashAmount,
|
|
uint32 maxBorrowRate,
|
|
bool redeemToUnderlying,
|
|
uint256 getId,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
bool useUnderlying = (depositAction ==
|
|
DepositActionType.DepositUnderlying ||
|
|
depositAction == DepositActionType.DepositUnderlyingAndMintNToken);
|
|
|
|
depositAmount = getDepositAmountAndSetApproval(
|
|
getId,
|
|
depositCurrencyId,
|
|
useUnderlying,
|
|
depositAmount
|
|
);
|
|
|
|
BalanceActionWithTrades[]
|
|
memory actions = getDepositCollateralBorrowAndWithdrawActions(
|
|
depositCurrencyId,
|
|
depositAction,
|
|
depositAmount,
|
|
borrowCurrencyId,
|
|
marketIndex,
|
|
fCashAmount,
|
|
maxBorrowRate,
|
|
redeemToUnderlying
|
|
);
|
|
|
|
uint256 msgValue = getMsgValue(
|
|
depositCurrencyId,
|
|
useUnderlying,
|
|
depositAmount
|
|
);
|
|
executeTradeActionWithBalanceChange(
|
|
actions,
|
|
msgValue,
|
|
borrowCurrencyId,
|
|
redeemToUnderlying,
|
|
setId
|
|
);
|
|
|
|
_eventName = "LogDepositCollateralBorrowAndWithdraw(address,bool,uint256,uint16,uint8,uint88,uint32,bool)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
useUnderlying,
|
|
depositAmount,
|
|
borrowCurrencyId,
|
|
marketIndex,
|
|
fCashAmount,
|
|
maxBorrowRate,
|
|
redeemToUnderlying
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Allows an account to withdraw from a fixed rate lend by selling the fCash back to the market. Equivalent to
|
|
* borrowing from the Notional perspective.
|
|
* @dev Setting the fCash amount and maxBorrowRate are best calculated using the Notional SDK off chain. Similar to borrowing,
|
|
* setting these amounts are a bit more forgiving since there is no change of reverts due to dust amounts.
|
|
* @param currencyId notional defined currency id of the lend asset to withdraw
|
|
* @param marketIndex the market index of the fCash asset. This is a number from 1 to 7 which corresponds to the tenor
|
|
* of the fCash asset. Tenors are described here: https://docs.notional.finance/notional-v2/quarterly-rolls/tenors
|
|
* @param fCashAmount amount of fCash at the marketIndex that should be sold
|
|
* @param maxBorrowRate the maximum interest rate that the account is willing to sell fCash at at, if set to zero the
|
|
* account will accept any rate
|
|
* @param setId sets the amount that the account has received when withdrawing its lend
|
|
*/
|
|
function withdrawLend(
|
|
uint16 currencyId,
|
|
uint8 marketIndex,
|
|
uint88 fCashAmount,
|
|
uint32 maxBorrowRate,
|
|
uint256 setId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
bool useUnderlying = currencyId != ETH_CURRENCY_ID;
|
|
BalanceActionWithTrades[] memory action = new BalanceActionWithTrades[](
|
|
1
|
|
);
|
|
action[0].actionType = DepositActionType.None;
|
|
action[0].currencyId = currencyId;
|
|
// Withdraw borrowed amount to wallet
|
|
action[0].withdrawEntireCashBalance = true;
|
|
action[0].redeemToUnderlying = useUnderlying;
|
|
|
|
bytes32[] memory trades = new bytes32[](1);
|
|
trades[0] = encodeBorrowTrade(marketIndex, fCashAmount, maxBorrowRate);
|
|
action[0].trades = trades;
|
|
|
|
executeTradeActionWithBalanceChange(
|
|
action,
|
|
0,
|
|
currencyId,
|
|
useUnderlying,
|
|
setId
|
|
);
|
|
|
|
_eventName = "LogWithdrawLend(address,uint16,uint8,uint88,uint32)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
currencyId,
|
|
marketIndex,
|
|
fCashAmount,
|
|
maxBorrowRate
|
|
);
|
|
}
|
|
|
|
/// @notice Mints sNOTE from the underlying BPT token.
|
|
/// @dev Mints sNOTE from the underlying BPT token.
|
|
/// @param bptAmount is the amount of BPT to transfer from the msg.sender.
|
|
function mintSNoteFromBPT(uint256 bptAmount)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
if (bptAmount == type(uint256).max)
|
|
bptAmount = bpt.balanceOf(address(this));
|
|
|
|
approve(bpt, address(staking), bptAmount);
|
|
|
|
staking.mintFromBPT(bptAmount);
|
|
|
|
_eventName = "LogMintSNoteFromBPT(address,uint256)";
|
|
_eventParam = abi.encode(address(this), bptAmount);
|
|
}
|
|
|
|
/// @notice Mints sNOTE from some amount of NOTE and ETH
|
|
/// @dev Mints sNOTE from some amount of NOTE and ETH
|
|
/// @param noteAmount amount of NOTE to transfer into the sNOTE contract
|
|
/// @param minBPT slippage parameter to prevent front running
|
|
function mintSNoteFromETH(
|
|
uint256 noteAmount,
|
|
uint256 ethAmount,
|
|
uint256 minBPT,
|
|
uint256 getId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
noteAmount = getUint(getId, noteAmount);
|
|
if (noteAmount == type(uint256).max)
|
|
noteAmount = note.balanceOf(address(this));
|
|
|
|
if (ethAmount == type(uint256).max) ethAmount = address(this).balance;
|
|
|
|
approve(note, address(staking), noteAmount);
|
|
|
|
staking.mintFromETH{ value: ethAmount }(noteAmount, minBPT);
|
|
|
|
_eventName = "LogMintSNoteFromETH(address,uint256,uint256,uint256)";
|
|
_eventParam = abi.encode(address(this), ethAmount, noteAmount, minBPT);
|
|
}
|
|
|
|
/// @notice Mints sNOTE from some amount of NOTE and WETH
|
|
/// @dev Mints sNOTE from some amount of NOTE and WETH
|
|
/// @param noteAmount amount of NOTE to transfer into the sNOTE contract
|
|
/// @param wethAmount amount of WETH to transfer into the sNOTE contract
|
|
/// @param minBPT slippage parameter to prevent front running
|
|
function mintSNoteFromWETH(
|
|
uint256 noteAmount,
|
|
uint256 wethAmount,
|
|
uint256 minBPT,
|
|
uint256 getId
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
noteAmount = getUint(getId, noteAmount);
|
|
if (noteAmount == type(uint256).max)
|
|
noteAmount = note.balanceOf(address(this));
|
|
|
|
if (wethAmount == type(uint256).max)
|
|
wethAmount = weth.balanceOf(address(this));
|
|
|
|
approve(note, address(staking), noteAmount);
|
|
approve(weth, address(staking), wethAmount);
|
|
|
|
staking.mintFromWETH(noteAmount, wethAmount, minBPT);
|
|
|
|
_eventName = "LogMintSNoteFromWETH(address,uint256,uint256,uint256)";
|
|
_eventParam = abi.encode(address(this), noteAmount, wethAmount, minBPT);
|
|
}
|
|
|
|
/// @notice Begins a cool down period for the sender
|
|
/// @dev This is required to redeem tokens
|
|
function startCoolDown()
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
staking.startCoolDown();
|
|
|
|
_eventName = "LogStartCoolDown(address)";
|
|
_eventParam = abi.encode(address(this));
|
|
}
|
|
|
|
/// @notice Stops a cool down for the sender
|
|
/// @dev User must start another cool down period in order to call redeemSNote
|
|
function stopCoolDown()
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
staking.stopCoolDown();
|
|
|
|
_eventName = "LogStopCoolDown(address)";
|
|
_eventParam = abi.encode(address(this));
|
|
}
|
|
|
|
/// @notice Redeems some amount of sNOTE to underlying constituent tokens (ETH and NOTE).
|
|
/// @dev An account must have passed its cool down expiration before they can redeem
|
|
/// @param sNOTEAmount amount of sNOTE to redeem
|
|
/// @param minWETH slippage protection for ETH/WETH amount
|
|
/// @param minNOTE slippage protection for NOTE amount
|
|
/// @param redeemWETH true if redeeming to WETH to ETH
|
|
function redeemSNote(
|
|
uint256 sNOTEAmount,
|
|
uint256 minWETH,
|
|
uint256 minNOTE,
|
|
bool redeemWETH
|
|
)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
if (sNOTEAmount == type(uint256).max)
|
|
sNOTEAmount = staking.balanceOf(address(this));
|
|
|
|
staking.redeem(sNOTEAmount, minWETH, minNOTE, redeemWETH);
|
|
|
|
_eventName = "LogRedeemSNote(address,uint256,uint256,uint256,bool)";
|
|
_eventParam = abi.encode(
|
|
address(this),
|
|
sNOTEAmount,
|
|
minWETH,
|
|
minNOTE,
|
|
redeemWETH
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Executes a number of batch actions on the account without getId or setId integration
|
|
* @dev This method will allow the user to take almost any action on Notional but does not have any
|
|
* getId or setId integration. This can be used to roll lends and borrows forward.
|
|
* @param actions a set of BatchActionWithTrades that will be executed for this account
|
|
*/
|
|
function batchActionRaw(BalanceActionWithTrades[] memory actions)
|
|
external
|
|
payable
|
|
returns (string memory _eventName, bytes memory _eventParam)
|
|
{
|
|
notional.batchBalanceAndTradeAction(address(this), actions);
|
|
|
|
_eventName = "LogBatchActionRaw(address)";
|
|
_eventParam = abi.encode(address(this));
|
|
}
|
|
}
|
|
|
|
contract ConnectV2Notional is NotionalResolver {
|
|
string public name = "Notional-v1.1";
|
|
}
|