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
Vaultinator Facet: The main contract that implements the vault management functionality
Diamond Storage: The storage pattern used by the Diamond Standard
Vaultinator Storage: The specific storage layout for the Vaultinator Facet
Diamond Cut Facet: The facet that handles adding, replacing, and removing facets
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 vaultvaultType: 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 vaultnewName: The new name of the vault
Returns:
boolindicating successAccess 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
Vaultstruct containing information about the vaultAccess 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 vaultasset: The address of the asset to depositamount: The amount of the asset to deposit
Returns:
boolindicating successAccess 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 vaultasset: The address of the asset to withdrawamount: The amount of the asset to withdraw
Returns:
boolindicating successAccess 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 vaultasset: 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 vaultuser: The address of the user to authorizerole: The role to assign to the user
Returns:
boolindicating successAccess 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 vaultuser: The address of the user to remove
Returns:
boolindicating successAccess 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 vaultuser: The address of the user
Returns:
boolindicating if the user is authorizedAccess 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 vaultuser: 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:
boolindicating successAccess 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:
boolindicating successAccess 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:
boolindicating if the address is an administratorAccess Control: Anyone can call this function
function pause() external returns (bool)Pauses all protocol operations.
Returns:
boolindicating successAccess Control: Only administrators can call this function
Events Emitted:
ProtocolPaused(address indexed admin)
function unpause() external returns (bool)Unpauses all protocol operations.
Returns:
boolindicating successAccess 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 addfunctionSelectors: The function selectors to add
Returns:
boolindicating successAccess 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 facetfunctionSelectors: The function selectors to replace
Returns:
boolindicating successAccess 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:
boolindicating successAccess 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:
Yieldinator Facet: For yield generation
Collatinator Facet: For collateralized lending
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.