Yieldinator Technical Details

The Yieldinator Facet is a core component of the Vaultinator Protocol that provides yield generation functionality. This document outlines the technical implementation details, including the contract architecture, function specifications, storage layout, and security considerations.

Contract Architecture

The Yieldinator Facet follows the Diamond Standard (EIP-2535) pattern and is implemented as a facet that can be added to the Vaultinator Diamond. It interacts with various DeFi protocols through a standardized adapter pattern.

Architecture Diagram

Component Interaction

  1. Yieldinator Facet: The main contract that implements the yield generation functionality

  2. Adapter Registry: A registry of protocol adapters that the Yieldinator can use

  3. Protocol Adapters: Standardized adapters for interacting with different DeFi protocols

  4. DeFi Protocols: External protocols that generate yield

Function Specifications

Protocol Management

function registerProtocol(address adapter) external returns (bool)

Registers a new protocol adapter in the Yieldinator.

  • Parameters:

    • adapter: The address of the protocol adapter

  • Returns: bool indicating success

  • Access Control: Only administrators can call this function

  • Events Emitted: ProtocolRegistered(address indexed adapter, string name)

function deregisterProtocol(address adapter) external returns (bool)

Deregisters a protocol adapter from the Yieldinator.

  • Parameters:

    • adapter: The address of the protocol adapter

  • Returns: bool indicating success

  • Access Control: Only administrators can call this function

  • Events Emitted: ProtocolDeregistered(address indexed adapter)

function getProtocols() external view returns (address[] memory)

Gets a list of all registered protocol adapters.

  • Returns: An array of protocol adapter addresses

  • Access Control: Anyone can call this function

Yield Operations

function deposit(address adapter, address asset, uint256 amount) external returns (uint256)

Deposits assets into a protocol to generate yield.

  • Parameters:

    • adapter: The address of the protocol adapter

    • asset: The address of the asset to deposit

    • amount: The amount of the asset to deposit

  • Returns: The amount deposited

  • Access Control: Anyone can call this function

  • Events Emitted: Deposited(address indexed user, address indexed adapter, address indexed asset, uint256 amount)

function withdraw(address adapter, address asset, uint256 amount) external returns (uint256)

Withdraws assets from a protocol.

  • Parameters:

    • adapter: The address of the protocol adapter

    • asset: The address of the asset to withdraw

    • amount: The amount of the asset to withdraw

  • Returns: The amount withdrawn

  • Access Control: Only the depositor can withdraw

  • Events Emitted: Withdrawn(address indexed user, address indexed adapter, address indexed asset, uint256 amount)

function harvestYield(address adapter, address asset) external returns (uint256)

Harvests yield generated by a protocol.

  • Parameters:

    • adapter: The address of the protocol adapter

    • asset: The address of the asset

  • Returns: The amount of yield harvested

  • Access Control: Only the depositor can harvest yield

  • Events Emitted: YieldHarvested(address indexed user, address indexed adapter, address indexed asset, uint256 amount)

Vault Integration

function depositFromVault(uint256 vaultId, address adapter, address asset, uint256 amount) external returns (uint256)

Deposits assets from a vault into a protocol.

  • Parameters:

    • vaultId: The ID of the vault

    • adapter: The address of the protocol adapter

    • asset: The address of the asset to deposit

    • amount: The amount of the asset to deposit

  • Returns: The amount deposited

  • Access Control: Only vault owners or authorized users can call this function

  • Events Emitted: VaultDeposited(uint256 indexed vaultId, address indexed adapter, address indexed asset, uint256 amount)

function withdrawToVault(uint256 vaultId, address adapter, address asset, uint256 amount) external returns (uint256)

Withdraws assets from a protocol to a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • adapter: The address of the protocol adapter

    • asset: The address of the asset to withdraw

    • amount: The amount of the asset to withdraw

  • Returns: The amount withdrawn

  • Access Control: Only vault owners or authorized users can call this function

  • Events Emitted: VaultWithdrawn(uint256 indexed vaultId, address indexed adapter, address indexed asset, uint256 amount)

Information and Metrics

function getProtocolAPR(address adapter, address asset) external view returns (uint256)

Gets the current APR for a protocol and asset.

  • Parameters:

    • adapter: The address of the protocol adapter

    • asset: The address of the asset

  • Returns: The APR in basis points (1/100 of a percent)

  • Access Control: Anyone can call this function

function getUserBalance(address user, address adapter, address asset) external view returns (uint256)

Gets the balance of a user in a protocol.

  • Parameters:

    • user: The address of the user

    • adapter: The address of the protocol adapter

    • asset: The address of the asset

  • Returns: The user's balance

  • Access Control: Anyone can call this function

function getYieldGenerated(address user, address adapter, address asset) external view returns (uint256)

Gets the yield generated by a user in a protocol.

  • Parameters:

    • user: The address of the user

    • adapter: The address of the protocol adapter

    • asset: The address of the asset

  • Returns: The yield generated

  • Access Control: Anyone can call this function

Emergency Operations

function emergencyWithdraw(address adapter, address asset) external returns (uint256)

Performs an emergency withdrawal from a protocol.

  • Parameters:

    • adapter: The address of the protocol adapter

    • asset: The address of the asset to withdraw

  • Returns: The amount withdrawn

  • Access Control: Only the depositor can perform an emergency withdrawal

  • Events Emitted: EmergencyWithdrawn(address indexed user, address indexed adapter, address indexed asset, uint256 amount)

function pause() external returns (bool)

Pauses all Yieldinator operations.

  • Returns: bool indicating success

  • Access Control: Only administrators can call this function

  • Events Emitted: YieldinatorPaused(address indexed admin)

function unpause() external returns (bool)

Unpauses all Yieldinator operations.

  • Returns: bool indicating success

  • Access Control: Only administrators can call this function

  • Events Emitted: YieldinatorUnpaused(address indexed admin)

Storage Layout

The Yieldinator Facet uses the Diamond Storage pattern to store its state. The storage layout is defined in the LibYieldinatorStorage library.

library LibYieldinatorStorage {
    bytes32 constant YIELDINATOR_STORAGE_POSITION = keccak256("yieldinator.core.storage");

    struct YieldinatorStorage {
        // Protocol registry
        mapping(address => Protocol) protocols;
        address[] protocolList;
        
        // User balances
        mapping(address => mapping(address => mapping(address => uint256))) userBalances;
        mapping(address => mapping(address => mapping(address => uint256))) userYieldGenerated;
        
        // Protocol configuration
        mapping(address => bool) approvedAdapters;
        mapping(address => mapping(address => YieldStrategy)) yieldStrategies;
        
        // Protocol metrics
        mapping(address => uint256) protocolTVL;
        uint256 totalValueLocked;
        
        // Reentrancy guard
        uint256 reentrancyStatus;
        
        // Pause status
        bool paused;
    }
    
    struct Protocol {
        address adapter;
        string name;
        bool active;
        uint256 registeredAt;
    }
    
    struct YieldStrategy {
        string name;
        bool autoCompounding;
        uint256 compoundingFrequency;
        address yieldToken;
    }
    
    function yieldinatorStorage() internal pure returns (YieldinatorStorage storage ds) {
        bytes32 position = YIELDINATOR_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }
}

Events

The Yieldinator Facet emits the following events:

event ProtocolRegistered(address indexed adapter, string name);
event ProtocolDeregistered(address indexed adapter);
event Deposited(address indexed user, address indexed adapter, address indexed asset, uint256 amount);
event Withdrawn(address indexed user, address indexed adapter, address indexed asset, uint256 amount);
event YieldHarvested(address indexed user, address indexed adapter, address indexed asset, uint256 amount);
event VaultDeposited(uint256 indexed vaultId, address indexed adapter, address indexed asset, uint256 amount);
event VaultWithdrawn(uint256 indexed vaultId, address indexed adapter, address indexed asset, uint256 amount);
event EmergencyWithdrawn(address indexed user, address indexed adapter, address indexed asset, uint256 amount);
event YieldinatorPaused(address indexed admin);
event YieldinatorUnpaused(address indexed admin);

Security Considerations

Reentrancy Protection

The Yieldinator Facet uses a reentrancy guard to prevent reentrancy attacks. All external functions that interact with other contracts are protected by the reentrancy guard.

modifier nonReentrant() {
    LibYieldinatorStorage.YieldinatorStorage storage s = LibYieldinatorStorage.yieldinatorStorage();
    require(s.reentrancyStatus != 2, "ReentrancyGuard: reentrant call");
    s.reentrancyStatus = 2;
    _;
    s.reentrancyStatus = 1;
}

Access Control

The Yieldinator Facet uses role-based access control to restrict access to certain functions. The access control is implemented through the Vaultinator Facet.

modifier onlyAdmin() {
    require(LibVaultinatorStorage.vaultinatorStorage().hasRole(msg.sender, "admin"), "YieldinatorFacet: not admin");
    _;
}

modifier onlyVaultOwner(uint256 vaultId) {
    require(LibVaultinatorStorage.vaultinatorStorage().vaults[vaultId].owner == msg.sender, "YieldinatorFacet: not vault owner");
    _;
}

Pause Mechanism

The Yieldinator Facet includes a pause mechanism that allows administrators to pause all operations in case of an emergency.

modifier whenNotPaused() {
    require(!LibYieldinatorStorage.yieldinatorStorage().paused, "YieldinatorFacet: paused");
    _;
}

function pause() external onlyAdmin returns (bool) {
    LibYieldinatorStorage.YieldinatorStorage storage s = LibYieldinatorStorage.yieldinatorStorage();
    require(!s.paused, "YieldinatorFacet: already paused");
    s.paused = true;
    emit YieldinatorPaused(msg.sender);
    return true;
}

function unpause() external onlyAdmin returns (bool) {
    LibYieldinatorStorage.YieldinatorStorage storage s = LibYieldinatorStorage.yieldinatorStorage();
    require(s.paused, "YieldinatorFacet: not paused");
    s.paused = false;
    emit YieldinatorUnpaused(msg.sender);
    return true;
}

Slippage Protection

The Yieldinator Facet includes slippage protection for token exchanges. When withdrawing assets, users can specify a minimum amount to receive.

function withdrawWithSlippage(address adapter, address asset, uint256 amount, uint256 minAmountOut) external nonReentrant whenNotPaused returns (uint256) {
    // Implementation details...
    require(amountOut >= minAmountOut, "YieldinatorFacet: slippage too high");
    // More implementation details...
    return amountOut;
}

Emergency Withdrawal

The Yieldinator Facet includes an emergency withdrawal function that allows users to withdraw their assets in case of an emergency, bypassing some of the normal checks.

function emergencyWithdraw(address adapter, address asset) external nonReentrant returns (uint256) {
    // Implementation details...
    // This function bypasses the pause check and some other checks
    // More implementation details...
    emit EmergencyWithdrawn(msg.sender, adapter, asset, amountOut);
    return amountOut;
}

Integration with Other Facets

The Yieldinator Facet integrates with other facets in the Vaultinator Protocol:

  1. Vaultinator Facet: For vault management and access control

  2. Collatinator Facet: For using yield-generating assets as collateral

  3. Stakinator Facet: For staking yield-generating assets

Vaultinator Integration

function depositFromVault(uint256 vaultId, address adapter, address asset, uint256 amount) external nonReentrant whenNotPaused onlyVaultOwner(vaultId) returns (uint256) {
    // Implementation details...
    // Transfer assets from vault to this contract
    // Deposit assets to protocol
    // Update vault balance
    // More implementation details...
    emit VaultDeposited(vaultId, adapter, asset, amount);
    return amount;
}

Collatinator Integration

function useAsCollateral(address adapter, address asset, uint256 amount, address debtAsset, uint256 debtAmount) external nonReentrant whenNotPaused returns (uint256) {
    // Implementation details...
    // Check if user has enough balance
    // Create collateralized position
    // More implementation details...
    return positionId;
}

Stakinator Integration

function stakeYieldToken(address adapter, address asset, uint256 amount, uint256 lockDuration) external nonReentrant whenNotPaused returns (uint256) {
    // Implementation details...
    // Check if user has enough balance
    // Stake yield token
    // More implementation details...
    return stakeId;
}

Supported DeFi Sectors

The Yieldinator Facet supports multiple DeFi sectors through its adapter pattern:

  1. Lending and Borrowing Protocols:

    • Aave

    • Compound

    • Maple Finance

  2. Automated Market Makers (AMMs) and Liquidity Provision:

    • Curve Finance

    • SushiSwap

  3. Yield Aggregators and Optimizers:

    • Yearn Finance

    • Convex Finance

    • Badger DAO

  4. Liquid Staking Protocols:

    • Lido

  5. Yield-Bearing Stablecoins:

    • Ethena

Each sector has its own set of adapters that implement the IYieldAdapter interface, providing a consistent API for interacting with different protocols.

Conclusion

The Yieldinator Facet is a powerful component of the Vaultinator Protocol that enables users to generate yield across multiple DeFi protocols. Its modular design, security features, and integration with other facets make it a flexible and robust solution for yield generation.