Users who want to mint YTokens using non-primary assets can do so by calling the deposit function on the Manager contract.
Upon deposit, the user receives a receipt NFT as confirmation of the order placement.
This request is then picked up by the Keeper bot, which sends a transaction on-chain to burn the receipt NFT and mint YTokens to the user's address.
/**
* @notice Deposit the asset to the vault
* @param _yToken address of the yToken
* @param _asset address of the asset
* @param _amount amount of the asset
* @param _receiver address of the receiver
* @param _callback address of the callback
* @param _callbackData data of the callback
* @dev This function is used to deposit the asset to the vault
*/
function deposit(address _yToken, address _asset, uint256 _amount, address _receiver, address _callback, bytes calldata _callbackData) external notPaused nonReentrant {
_validate(msg.sender, _receiver, _yToken, _asset, _amount, true);
IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);
// get absolute exchange rate
uint256 exchangeRateInUnderlying = IYToken(_yToken).exchangeRate();
// For all deposit via Manager, we mint the receipt and follow 2 step process
// callback and callbackData are only for future use and can only be enabled by upgrading the contract
uint256 receiptId = IReceipt(receipt).mint(msg.sender, Order(true, msg.sender, _asset, _receiver, _yToken, _amount, block.timestamp, exchangeRateInUnderlying, address(0), ""));
emit OrderRequest(msg.sender, _yToken, _asset, _receiver, _amount, true, exchangeRateInUnderlying, receiptId);
}
Redeem YToken using non-Primary Asset
Users can also place a redeem request for YUSD through the Manager contract.
These requests are maintained in a queue until the cooldown period is complete.
Once the cooldown period ends, the Keeper bot processes the redeem request and transfers the underlying asset to the user.
/**
* @notice Redeem the asset from the vault
* @param _yToken address of the yToken
* @param _asset address of the asset
* @param _shares amount of the shares
* @param _receiver address of the receiver
* @param _callback address of the callback
* @param _callbackData data of the callback
* @dev This function is used to redeem the asset from the vault
*
* @dev Example:
* When redeeming 100e18 YToken with exchange rate 1 YToken = 1.1 USDC:
* 1. Calculate vaultAssetAmount = 110e6 USDC (using convertToAssets)
* 2. Update yToken's total assets accounting to reflect the withdrawn amount
* 3. Burn the yToken shares immediately to stop yield accrual
* 4. Create a receipt for the withdrawal that can be executed after the waiting period
*/
function redeem(address caller, address _yToken, address _asset, uint256 _shares, address _receiver, address _callback, bytes calldata _callbackData) external notPaused nonReentrant {
if (msg.sender == _yToken) {
_validate(caller, _receiver, _yToken, _asset, _shares, false);
} else {
require(caller == msg.sender, "!caller");
_validate(msg.sender, _receiver, _yToken, _asset, _shares, false);
}
// Calculate the equivalent vault asset amount
uint256 vaultAssetAmount = IERC4626(_yToken).convertToAssets(_shares);
// update equivalent total assets
IYToken(_yToken).updateTotalAssets(vaultAssetAmount, false);
// burn shares from caller
IYToken(_yToken).burnYToken(caller, _shares);
// get exchange rate in underlying
uint256 exchangeRateInUnderlying = IYToken(_yToken).exchangeRate();
// callback and callbackData are only for future use and can only be enabled by upgrading the contract
uint256 receiptId = IReceipt(receipt).mint(caller, Order(false, caller, _asset, _receiver, _yToken, _shares, block.timestamp, exchangeRateInUnderlying, address(0), ""));
emit OrderRequest(caller, _yToken, _asset, _receiver, _shares, false, exchangeRateInUnderlying, receiptId); // add receiver
}