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
Yieldinator Facet: The main contract that implements the yield generation functionality
Adapter Registry: A registry of protocol adapters that the Yieldinator can use
Protocol Adapters: Standardized adapters for interacting with different DeFi protocols
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:
boolindicating successAccess 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:
boolindicating successAccess 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 adapterasset: The address of the asset to depositamount: 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 adapterasset: The address of the asset to withdrawamount: 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 adapterasset: 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 vaultadapter: The address of the protocol adapterasset: The address of the asset to depositamount: 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 vaultadapter: The address of the protocol adapterasset: The address of the asset to withdrawamount: 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 adapterasset: 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 useradapter: The address of the protocol adapterasset: 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 useradapter: The address of the protocol adapterasset: 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 adapterasset: 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:
boolindicating successAccess Control: Only administrators can call this function
Events Emitted:
YieldinatorPaused(address indexed admin)
function unpause() external returns (bool)Unpauses all Yieldinator operations.
Returns:
boolindicating successAccess 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:
Vaultinator Facet: For vault management and access control
Collatinator Facet: For using yield-generating assets as collateral
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:
Lending and Borrowing Protocols:
Aave
Compound
Maple Finance
Automated Market Makers (AMMs) and Liquidity Provision:
Curve Finance
SushiSwap
Yield Aggregators and Optimizers:
Yearn Finance
Convex Finance
Badger DAO
Liquid Staking Protocols:
Lido
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.