Vaultinator Technical Details

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

Contract Architecture

The Vaultinator Facet follows the Diamond Standard (EIP-2535) pattern and is implemented as the primary facet of the Vaultinator Diamond. It manages vaults, assets, and access control for the entire protocol.

Class Diagram

┌─────────────────┐      ┌───────────────────┐      ┌───────────────────┐
│  VaultinatorFacet│─────►│  YieldinatorFacet │─────►│  CollatinatorFacet│
└─────────────────┘      └───────────────────┘      └───────────────────┘
         │                         ▲                          ▲
         │                         │                          │
         ▼                         │                          │
┌─────────────────┐      ┌───────────────────┐      ┌───────────────────┐
│  DiamondStorage  │─────►│StakinatorFacet    │      │  DiamondCutFacet  │
└─────────────────┘      └───────────────────┘      └───────────────────┘
         │                                                    ▲
         │                                                    │
         ▼                                                    │
┌─────────────────┐                                  ┌───────────────────┐
│VaultinatorStorage│                                  │DiamondLoupeFacet  │
└─────────────────┘                                  └───────────────────┘

Component Interaction

  1. Vaultinator Facet: The main contract that implements the vault management functionality

  2. Diamond Storage: The storage pattern used by the Diamond Standard

  3. Vaultinator Storage: The specific storage layout for the Vaultinator Facet

  4. Diamond Cut Facet: The facet that handles adding, replacing, and removing facets

  5. Diamond Loupe Facet: The facet that provides introspection functions for the diamond

Function Specifications

Vault Management

function createVault(string calldata name, VaultType vaultType) external returns (uint256)

Creates a new vault.

  • Parameters:

    • name: The name of the vault

    • vaultType: The type of the vault (PERSONAL, MULTISIG, or DAO)

  • Returns: The ID of the created vault

  • Access Control: Anyone can call this function

  • Events Emitted: VaultCreated(uint256 indexed vaultId, address indexed owner, string name, VaultType vaultType)

function renameVault(uint256 vaultId, string calldata newName) external returns (bool)

Renames an existing vault.

  • Parameters:

    • vaultId: The ID of the vault

    • newName: The new name of the vault

  • Returns: bool indicating success

  • Access Control: Only the vault owner can call this function

  • Events Emitted: VaultRenamed(uint256 indexed vaultId, string newName)

function getVault(uint256 vaultId) external view returns (Vault memory)

Gets information about a vault.

  • Parameters:

    • vaultId: The ID of the vault

  • Returns: A Vault struct containing information about the vault

  • Access Control: Anyone can call this function

function getUserVaults(address user) external view returns (uint256[] memory)

Gets a list of all vault IDs for a user.

  • Parameters:

    • user: The address of the user

  • Returns: An array of vault IDs

  • Access Control: Anyone can call this function

Asset Management

function deposit(uint256 vaultId, address asset, uint256 amount) external returns (bool)

Deposits assets into a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • asset: The address of the asset to deposit

    • amount: The amount of the asset to deposit

  • Returns: bool indicating success

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

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

function withdraw(uint256 vaultId, address asset, uint256 amount) external returns (bool)

Withdraws assets from a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • asset: The address of the asset to withdraw

    • amount: The amount of the asset to withdraw

  • Returns: bool indicating success

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

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

function getVaultAssets(uint256 vaultId) external view returns (address[] memory)

Gets a list of all assets in a vault.

  • Parameters:

    • vaultId: The ID of the vault

  • Returns: An array of asset addresses

  • Access Control: Anyone can call this function

function getVaultBalance(uint256 vaultId, address asset) external view returns (uint256)

Gets the balance of an asset in a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • asset: The address of the asset

  • Returns: The balance of the asset

  • Access Control: Anyone can call this function

Access Control

function addAuthorizedUser(uint256 vaultId, address user, bytes32 role) external returns (bool)

Adds an authorized user to a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • user: The address of the user to authorize

    • role: The role to assign to the user

  • Returns: bool indicating success

  • Access Control: Only the vault owner can call this function

  • Events Emitted: AuthorizedUserAdded(uint256 indexed vaultId, address indexed user, bytes32 role)

function removeAuthorizedUser(uint256 vaultId, address user) external returns (bool)

Removes an authorized user from a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • user: The address of the user to remove

  • Returns: bool indicating success

  • Access Control: Only the vault owner can call this function

  • Events Emitted: AuthorizedUserRemoved(uint256 indexed vaultId, address indexed user)

function isAuthorizedUser(uint256 vaultId, address user) external view returns (bool)

Checks if a user is authorized for a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • user: The address of the user

  • Returns: bool indicating if the user is authorized

  • Access Control: Anyone can call this function

function getUserRole(uint256 vaultId, address user) external view returns (bytes32)

Gets the role of a user for a vault.

  • Parameters:

    • vaultId: The ID of the vault

    • user: The address of the user

  • Returns: The role of the user

  • Access Control: Anyone can call this function

Protocol Administration

function addAdmin(address admin) external returns (bool)

Adds an administrator to the protocol.

  • Parameters:

    • admin: The address of the administrator to add

  • Returns: bool indicating success

  • Access Control: Only the contract owner can call this function

  • Events Emitted: AdminAdded(address indexed admin)

function removeAdmin(address admin) external returns (bool)

Removes an administrator from the protocol.

  • Parameters:

    • admin: The address of the administrator to remove

  • Returns: bool indicating success

  • Access Control: Only the contract owner can call this function

  • Events Emitted: AdminRemoved(address indexed admin)

function isAdmin(address admin) external view returns (bool)

Checks if an address is an administrator.

  • Parameters:

    • admin: The address to check

  • Returns: bool indicating if the address is an administrator

  • Access Control: Anyone can call this function

function pause() external returns (bool)

Pauses all protocol operations.

  • Returns: bool indicating success

  • Access Control: Only administrators can call this function

  • Events Emitted: ProtocolPaused(address indexed admin)

function unpause() external returns (bool)

Unpauses all protocol operations.

  • Returns: bool indicating success

  • Access Control: Only administrators can call this function

  • Events Emitted: ProtocolUnpaused(address indexed admin)

Facet Management

function addFacet(address facet, bytes4[] calldata functionSelectors) external returns (bool)

Adds a new facet to the diamond.

  • Parameters:

    • facet: The address of the facet to add

    • functionSelectors: The function selectors to add

  • Returns: bool indicating success

  • Access Control: Only the contract owner can call this function

  • Events Emitted: FacetAdded(address indexed facet, bytes4[] functionSelectors)

function replaceFacet(address facet, bytes4[] calldata functionSelectors) external returns (bool)

Replaces an existing facet in the diamond.

  • Parameters:

    • facet: The address of the new facet

    • functionSelectors: The function selectors to replace

  • Returns: bool indicating success

  • Access Control: Only the contract owner can call this function

  • Events Emitted: FacetReplaced(address indexed facet, bytes4[] functionSelectors)

function removeFacet(bytes4[] calldata functionSelectors) external returns (bool)

Removes a facet from the diamond.

  • Parameters:

    • functionSelectors: The function selectors to remove

  • Returns: bool indicating success

  • Access Control: Only the contract owner can call this function

  • Events Emitted: FacetRemoved(bytes4[] functionSelectors)

Storage Layout

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

library LibVaultinatorStorage {
    bytes32 constant VAULTINATOR_STORAGE_POSITION = keccak256("vaultinator.core.storage");

    struct VaultinatorStorage {
        // Vault management
        mapping(uint256 => Vault) vaults;
        mapping(address => uint256[]) userVaults;
        uint256 nextVaultId;
        
        // Asset management
        mapping(uint256 => mapping(address => uint256)) vaultBalances;
        mapping(uint256 => address[]) vaultAssets;
        
        // Access control
        mapping(uint256 => mapping(address => bytes32)) vaultUserRoles;
        mapping(address => bool) admins;
        address owner;
        
        // Protocol status
        bool paused;
        
        // Reentrancy guard
        uint256 reentrancyStatus;
    }
    
    struct Vault {
        uint256 id;
        address owner;
        string name;
        VaultType vaultType;
        uint256 createdAt;
        bool active;
    }
    
    enum VaultType { PERSONAL, MULTISIG, DAO }
    
    function vaultinatorStorage() internal pure returns (VaultinatorStorage storage ds) {
        bytes32 position = VAULTINATOR_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }
}

Events

The Vaultinator Facet emits the following events:

event VaultCreated(uint256 indexed vaultId, address indexed owner, string name, VaultType vaultType);
event VaultRenamed(uint256 indexed vaultId, string newName);
event Deposited(uint256 indexed vaultId, address indexed asset, uint256 amount);
event Withdrawn(uint256 indexed vaultId, address indexed asset, uint256 amount);
event AuthorizedUserAdded(uint256 indexed vaultId, address indexed user, bytes32 role);
event AuthorizedUserRemoved(uint256 indexed vaultId, address indexed user);
event AdminAdded(address indexed admin);
event AdminRemoved(address indexed admin);
event ProtocolPaused(address indexed admin);
event ProtocolUnpaused(address indexed admin);
event FacetAdded(address indexed facet, bytes4[] functionSelectors);
event FacetReplaced(address indexed facet, bytes4[] functionSelectors);
event FacetRemoved(bytes4[] functionSelectors);

Security Considerations

Reentrancy Protection

The Vaultinator 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() {
    LibVaultinatorStorage.VaultinatorStorage storage s = LibVaultinatorStorage.vaultinatorStorage();
    require(s.reentrancyStatus != 2, "ReentrancyGuard: reentrant call");
    s.reentrancyStatus = 2;
    _;
    s.reentrancyStatus = 1;
}

Access Control

The Vaultinator Facet uses role-based access control to restrict access to certain functions. The access control is implemented through the vaultUserRoles mapping and the admins mapping.

modifier onlyOwner() {
    require(msg.sender == LibVaultinatorStorage.vaultinatorStorage().owner, "VaultinatorFacet: not owner");
    _;
}

modifier onlyAdmin() {
    require(LibVaultinatorStorage.vaultinatorStorage().admins[msg.sender], "VaultinatorFacet: not admin");
    _;
}

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

modifier onlyAuthorizedUser(uint256 vaultId) {
    LibVaultinatorStorage.VaultinatorStorage storage s = LibVaultinatorStorage.vaultinatorStorage();
    require(s.vaults[vaultId].owner == msg.sender || s.vaultUserRoles[vaultId][msg.sender] != bytes32(0), "VaultinatorFacet: not authorized");
    _;
}

Pause Mechanism

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

modifier whenNotPaused() {
    require(!LibVaultinatorStorage.vaultinatorStorage().paused, "VaultinatorFacet: paused");
    _;
}

function pause() external onlyAdmin returns (bool) {
    LibVaultinatorStorage.VaultinatorStorage storage s = LibVaultinatorStorage.vaultinatorStorage();
    require(!s.paused, "VaultinatorFacet: already paused");
    s.paused = true;
    emit ProtocolPaused(msg.sender);
    return true;
}

function unpause() external onlyAdmin returns (bool) {
    LibVaultinatorStorage.VaultinatorStorage storage s = LibVaultinatorStorage.vaultinatorStorage();
    require(s.paused, "VaultinatorFacet: not paused");
    s.paused = false;
    emit ProtocolUnpaused(msg.sender);
    return true;
}

Ownership Transfer

The Vaultinator Facet includes a secure ownership transfer mechanism to prevent accidental transfers.

function transferOwnership(address newOwner) external onlyOwner returns (bool) {
    require(newOwner != address(0), "VaultinatorFacet: new owner is the zero address");
    LibVaultinatorStorage.VaultinatorStorage storage s = LibVaultinatorStorage.vaultinatorStorage();
    address oldOwner = s.owner;
    s.owner = newOwner;
    emit OwnershipTransferred(oldOwner, newOwner);
    return true;
}

Vault Ownership Transfer

The Vaultinator Facet includes a secure vault ownership transfer mechanism.

function transferVaultOwnership(uint256 vaultId, address newOwner) external onlyVaultOwner(vaultId) returns (bool) {
    require(newOwner != address(0), "VaultinatorFacet: new owner is the zero address");
    LibVaultinatorStorage.VaultinatorStorage storage s = LibVaultinatorStorage.vaultinatorStorage();
    
    // Remove vault from old owner's list
    uint256[] storage oldOwnerVaults = s.userVaults[s.vaults[vaultId].owner];
    for (uint256 i = 0; i < oldOwnerVaults.length; i++) {
        if (oldOwnerVaults[i] == vaultId) {
            oldOwnerVaults[i] = oldOwnerVaults[oldOwnerVaults.length - 1];
            oldOwnerVaults.pop();
            break;
        }
    }
    
    // Add vault to new owner's list
    s.userVaults[newOwner].push(vaultId);
    
    // Update vault owner
    address oldOwner = s.vaults[vaultId].owner;
    s.vaults[vaultId].owner = newOwner;
    
    emit VaultOwnershipTransferred(vaultId, oldOwner, newOwner);
    return true;
}

Integration with Other Facets

The Vaultinator Facet is the core facet of the protocol and integrates with all other facets:

  1. Yieldinator Facet: For yield generation

  2. Collatinator Facet: For collateralized lending

  3. Stakinator Facet: For staking

Yieldinator Integration

function depositToYieldinator(uint256 vaultId, address adapter, address asset, uint256 amount) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (uint256) {
    // Implementation details...
    // Check if vault has enough balance
    // Transfer assets to Yieldinator
    // Update vault balance
    // More implementation details...
    return amount;
}

function withdrawFromYieldinator(uint256 vaultId, address adapter, address asset, uint256 amount) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (uint256) {
    // Implementation details...
    // Withdraw assets from Yieldinator
    // Update vault balance
    // More implementation details...
    return amount;
}

Collatinator Integration

function createPositionFromVault(
    uint256 vaultId,
    address protocol,
    address collateralAsset,
    uint256 collateralAmount,
    address debtAsset,
    uint256 debtAmount
) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (uint256) {
    // Implementation details...
    // Check if vault has enough balance
    // Transfer collateral to Collatinator
    // Create position
    // Update vault balance
    // More implementation details...
    return positionId;
}

function closePositionToVault(uint256 vaultId, uint256 positionId) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (bool) {
    // Implementation details...
    // Close position
    // Transfer assets to vault
    // Update vault balance
    // More implementation details...
    return true;
}

Stakinator Integration

function stakeFromVault(uint256 vaultId, uint256 poolId, uint256 amount, uint256 lockDuration) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (uint256) {
    // Implementation details...
    // Check if vault has enough balance
    // Transfer assets to Stakinator
    // Create stake
    // Update vault balance
    // More implementation details...
    return stakeId;
}

function unstakeToVault(uint256 vaultId, uint256 stakeId) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (uint256) {
    // Implementation details...
    // Unstake assets
    // Transfer assets to vault
    // Update vault balance
    // More implementation details...
    return amount;
}

Multi-Chain Support

The Vaultinator Facet includes support for cross-chain vault management, allowing users to manage assets across multiple blockchains.

Cross-Chain Vault Creation

function createCrossChainVault(
    string calldata name,
    VaultType vaultType,
    uint256 targetChainId
) external nonReentrant whenNotPaused returns (uint256) {
    // Implementation details...
    // Create vault on current chain
    // Send message to target chain to create vault
    // More implementation details...
    return vaultId;
}

Cross-Chain Asset Transfer

function transferAssetCrossChain(
    uint256 sourceVaultId,
    uint256 targetVaultId,
    uint256 targetChainId,
    address asset,
    uint256 amount
) external nonReentrant whenNotPaused onlyAuthorizedUser(sourceVaultId) returns (bool) {
    // Implementation details...
    // Check if source vault has enough balance
    // Bridge assets to target chain
    // Update source vault balance
    // More implementation details...
    return true;
}

Vault Types

The Vaultinator Facet supports multiple vault types:

Personal Vault

Personal vaults are owned by a single user and can be managed by that user and any authorized users.

function createPersonalVault(string calldata name) external nonReentrant whenNotPaused returns (uint256) {
    return _createVault(name, VaultType.PERSONAL);
}

Multisig Vault

Multisig vaults require multiple signatures to perform certain operations.

function createMultisigVault(
    string calldata name,
    address[] calldata signers,
    uint256 threshold
) external nonReentrant whenNotPaused returns (uint256) {
    // Implementation details...
    // Create vault
    // Set up multisig configuration
    // More implementation details...
    return vaultId;
}

function proposeTransaction(
    uint256 vaultId,
    address target,
    uint256 value,
    bytes calldata data
) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (uint256) {
    // Implementation details...
    // Create transaction proposal
    // More implementation details...
    return proposalId;
}

function confirmTransaction(uint256 vaultId, uint256 proposalId) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (bool) {
    // Implementation details...
    // Confirm transaction proposal
    // Execute if threshold is reached
    // More implementation details...
    return true;
}

DAO Vault

DAO vaults are governed by token holders and use a voting mechanism for decision-making.

function createDAOVault(
    string calldata name,
    address governanceToken,
    uint256 quorum,
    uint256 votingPeriod
) external nonReentrant whenNotPaused returns (uint256) {
    // Implementation details...
    // Create vault
    // Set up DAO configuration
    // More implementation details...
    return vaultId;
}

function proposeVote(
    uint256 vaultId,
    address target,
    uint256 value,
    bytes calldata data,
    string calldata description
) external nonReentrant whenNotPaused onlyAuthorizedUser(vaultId) returns (uint256) {
    // Implementation details...
    // Create vote proposal
    // More implementation details...
    return proposalId;
}

function castVote(uint256 vaultId, uint256 proposalId, bool support) external nonReentrant whenNotPaused returns (bool) {
    // Implementation details...
    // Cast vote
    // Execute if quorum is reached and voting period is over
    // More implementation details...
    return true;
}

Conclusion

The Vaultinator Facet is the core component of the Vaultinator Protocol that enables users to create and manage vaults for their assets. Its modular design, security features, and integration with other facets make it a flexible and robust solution for asset management.