YieldFi
  • Introduction
  • Problem & Solution
  • How It Works
  • FAQs
  • USPs
  • Technical Docs
    • YToken Vaults
      • YUSD
      • YETH
      • YBTC
      • YLP
    • Architecture
    • Smart Contract Interaction
  • Guides
    • Mint
    • Swap
  • Rewards Program
    • LP Program
  • Concepts
    • Transparency
    • Custody Solution
    • Risk Management
    • Reserve Fund
  • Resources
    • V2 Contract Addresses
      • Old Contract Addresses
    • Audits
    • Oracles
    • Brand Kit
    • General Risk Disclosures
    • Privacy Policy
    • Terms of Service
Powered by GitBook
On this page
  • Mint YToken using Primary Asset
  • Redeem YToken to Primary Asset
  • Mint YToken using non-Primary Asset via Manager
  • Redeem YToken using non-Primary Asset via Manager
  1. Technical Docs

Smart Contract Interaction

Mint YToken using Primary Asset

  1. Since our vault follows ERC 4626 stadard, YToken can be minted instantly using Primary Asset YToken directly by calling deposit function on Vault contract.

    function deposit(uint256 assets, address receiver) public virtual returns (uint256) {
        uint256 maxAssets = maxDeposit(receiver);
        if (assets > maxAssets) {
            revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets);
        }

        uint256 shares = previewDeposit(assets);
        _deposit(_msgSender(), receiver, assets, shares);

        return shares;
    }

Redeem YToken to Primary Asset

  1. Redeeming YTokens for the primary asset token, can be done by calling redeem function on the Vault contract.

  2. The Vault contract then places a redeem request on the Manager contract on behalf of the user.

  3. Redeem requests are processed in a queue by the Keeper bot after a cooldown period.

    function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) {
        uint256 maxShares = maxRedeem(owner);
        if (shares > maxShares) {
            revert ERC4626ExceededMaxRedeem(owner, shares, maxShares);
        }

        uint256 assets = previewRedeem(shares);
        _withdraw(_msgSender(), receiver, owner, assets, shares);

        return assets;
    }

Mint YToken using non-Primary Asset via Manager

  1. Users who want to mint YTokens using non-primary assets can do so by calling the deposit function on the Manager contract (along with passing _referralCode if they have any).

  2. Upon deposit, the user receives a receipt NFT as confirmation of the order placement.

  3. 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
     * @param _referralCode bytes32 referral code for on-chain tracking
     * @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, bytes32 _referralCode) 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), "", _referralCode));
        emit OrderRequest(msg.sender, _yToken, _asset, _receiver, _amount, true, exchangeRateInUnderlying, receiptId, _referralCode);
    }

Redeem YToken using non-Primary Asset via Manager

  1. Users can also place a redeem request for YUSD through the Manager contract.

  2. These requests are maintained in a queue until the cooldown period is complete.

  3. 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);

        /**
         * Post burning token, check the remaining shares for caller is either 0 or >= minSharesInYToken
         * This is to ensure future redeems are not blocked due to low shares
         */
        uint256 remainingShares = IERC20(_yToken).balanceOf(caller);
        require(remainingShares == 0 || remainingShares >= minSharesInYToken[_yToken], "0 < remainingShares < minShares");

        // 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, ""); 
    }

PreviousArchitectureNextMint

Last updated 1 month ago