Vaultinator Facet Integration Guide
This guide provides developers with the information needed to integrate with the Vaultinator Facet, the core component of the Vaultinator Protocol. It covers the basic interaction patterns, contract interfaces, and best practices for building applications that leverage vault functionality.
Interface Overview
The Vaultinator Facet exposes a comprehensive set of functions through the IVaultinatorFacet interface:
interface IVaultinatorFacet {
// Vault management
function createVault(string calldata name, VaultType vaultType) external returns (uint256 vaultId);
function deposit(uint256 vaultId, address asset, uint256 amount) external returns (bool);
function withdraw(uint256 vaultId, address asset, uint256 amount) external returns (bool);
function transferBetweenVaults(uint256 fromVaultId, uint256 toVaultId, address asset, uint256 amount) external returns (bool);
// Access control
function grantAccess(uint256 vaultId, address user, bytes32 role) external returns (bool);
function revokeAccess(uint256 vaultId, address user, bytes32 role) external returns (bool);
function hasRole(uint256 vaultId, address user, bytes32 role) external view returns (bool);
// Vault configuration
function updateVaultConfig(uint256 vaultId, bytes calldata configData) external returns (bool);
function setVaultStrategy(uint256 vaultId, address strategy) external returns (bool);
function getVaultConfig(uint256 vaultId) external view returns (VaultConfig memory);
// Protocol administration
function updateProtocolParams(bytes calldata paramsData) external returns (bool);
function setProtocolFee(uint256 feePercentage) external returns (bool);
function pauseProtocol() external returns (bool);
function unpauseProtocol() external returns (bool);
// View functions
function getVault(uint256 vaultId) external view returns (VaultInfo memory);
function getUserVaults(address user) external view returns (uint256[] memory);
function getVaultAssets(uint256 vaultId) external view returns (AssetInfo[] memory);
function getVaultBalance(uint256 vaultId, address asset) external view returns (uint256);
}Basic Integration Pattern
To integrate with the Vaultinator Facet, you'll need to:
Import the appropriate interface
Create a contract instance using the Diamond address
Call functions on the facet through the Diamond
Example in Solidity
// Import the interface
import "@vaultinator/interfaces/IVaultinatorFacet.sol";
contract MyDApp {
IVaultinatorFacet public vaultinator;
constructor(address _vaultinatorDiamond) {
// Create instance of the facet through the Diamond
vaultinator = IVaultinatorFacet(_vaultinatorDiamond);
}
function createUserVault(string calldata name) external returns (uint256) {
// Create a personal vault
return vaultinator.createVault(name, IVaultinatorFacet.VaultType.PERSONAL);
}
function depositToVault(uint256 vaultId, address asset, uint256 amount) external {
// Approve tokens
IERC20(asset).approve(address(vaultinator), amount);
// Deposit to vault
vaultinator.deposit(vaultId, asset, amount);
}
}Example in JavaScript (ethers.js)
const { ethers } = require("ethers");
const VaultinatorABI = require("./abis/IVaultinatorFacet.json");
async function createVault(signer, name) {
// Create contract instance
const vaultinatorAddress = "0x..."; // Diamond address
const vaultinator = new ethers.Contract(vaultinatorAddress, VaultinatorABI, signer);
// Create vault (VaultType.PERSONAL = 0)
const tx = await vaultinator.createVault(name, 0);
const receipt = await tx.wait();
// Get vault ID from event
const vaultCreatedEvent = receipt.events.find(e => e.event === "VaultCreated");
const vaultId = vaultCreatedEvent.args.vaultId;
return vaultId;
}
async function depositToVault(signer, vaultId, assetAddress, amount) {
// Create contract instances
const vaultinatorAddress = "0x..."; // Diamond address
const vaultinator = new ethers.Contract(vaultinatorAddress, VaultinatorABI, signer);
const asset = new ethers.Contract(assetAddress, ERC20ABI, signer);
// Approve tokens
await asset.approve(vaultinatorAddress, amount);
// Deposit to vault
const tx = await vaultinator.deposit(vaultId, assetAddress, amount);
await tx.wait();
return tx;
}Common Integration Scenarios
1. Creating and Managing Vaults
// Create a vault
const vaultId = await createVault(signer, "My Personal Vault");
// Get vault information
const vaultInfo = await vaultinator.getVault(vaultId);
console.log(`Vault Name: ${vaultInfo.name}`);
console.log(`Vault Owner: ${vaultInfo.owner}`);
console.log(`Vault Type: ${vaultInfo.vaultType === 0 ? "Personal" : vaultInfo.vaultType === 1 ? "Shared" : "Institutional"}`);
// Get user's vaults
const userVaults = await vaultinator.getUserVaults(await signer.getAddress());
console.log(`User has ${userVaults.length} vaults`);2. Managing Vault Assets
// Deposit assets to a vault
const daiToken = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; // DAI address
const depositAmount = ethers.utils.parseEther("100"); // 100 DAI
await depositToVault(signer, vaultId, daiToken, depositAmount);
// Check vault balance
const balance = await vaultinator.getVaultBalance(vaultId, daiToken);
console.log(`Vault DAI Balance: ${ethers.utils.formatEther(balance)}`);
// Withdraw assets from a vault
const withdrawAmount = ethers.utils.parseEther("50"); // 50 DAI
await vaultinator.withdraw(vaultId, daiToken, withdrawAmount);
// Transfer assets between vaults
const otherVaultId = 2; // Another vault ID
await vaultinator.transferBetweenVaults(vaultId, otherVaultId, daiToken, ethers.utils.parseEther("25"));3. Managing Vault Access
// Define roles
const MANAGER_ROLE = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("MANAGER_ROLE"));
const DEPOSITOR_ROLE = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("DEPOSITOR_ROLE"));
// Grant access to another user
const otherUser = "0x..."; // Address of another user
await vaultinator.grantAccess(vaultId, otherUser, MANAGER_ROLE);
// Check if user has role
const hasRole = await vaultinator.hasRole(vaultId, otherUser, MANAGER_ROLE);
console.log(`User has MANAGER_ROLE: ${hasRole}`);
// Revoke access
await vaultinator.revokeAccess(vaultId, otherUser, MANAGER_ROLE);4. Integrating with Other Facets
// Deploy vault assets to yield protocol via Yieldinator
const aaveAdapter = "0x..."; // Aave adapter address
// First, get the Yieldinator facet through the Diamond
const yieldinatorABI = require("./abis/IYieldinatorFacet.json");
const yieldinator = new ethers.Contract(vaultinatorAddress, yieldinatorABI, signer);
// Deploy assets from vault to yield protocol
await vaultinator.deployToYieldProtocol(vaultId, daiToken, depositAmount, aaveAdapter);
// Check deployed balance
const deployedBalance = await yieldinator.getUserBalance(await signer.getAddress(), aaveAdapter, daiToken);
console.log(`Deployed Balance: ${ethers.utils.formatEther(deployedBalance)}`);
// Create collateralized position via Collatinator
const skyMoneyAdapter = "0x..."; // Sky.money (formerly MakerDAO) adapter address
const ethToken = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; // WETH address
// Get the Collatinator facet through the Diamond
const collatinatorABI = require("./abis/ICollatinatorFacet.json");
const collatinator = new ethers.Contract(vaultinatorAddress, collatinatorABI, signer);
// Create position from vault
const positionId = await vaultinator.createCollateralizedPosition(
vaultId,
ethToken,
ethers.utils.parseEther("10"), // 10 ETH collateral
daiToken,
ethers.utils.parseEther("15000"), // 15,000 DAI debt
skyMoneyAdapter
);
// Check position details
const position = await collatinator.getPosition(positionId);
console.log(`Health Factor: ${ethers.utils.formatUnits(position.healthFactor, 2)}`);Event Monitoring
The Vaultinator Facet emits events for all significant actions. Monitoring these events is crucial for building responsive applications.
Key Events
// Vault events
event VaultCreated(uint256 indexed vaultId, address indexed owner, string name, VaultType vaultType);
event Deposited(uint256 indexed vaultId, address indexed asset, uint256 amount, address depositor);
event Withdrawn(uint256 indexed vaultId, address indexed asset, uint256 amount, address recipient);
event VaultStrategyUpdated(uint256 indexed vaultId, address indexed strategy);
// Access control events
event AccessGranted(uint256 indexed vaultId, address indexed user, bytes32 indexed role);
event AccessRevoked(uint256 indexed vaultId, address indexed user, bytes32 indexed role);
// Protocol events
event ProtocolFeeUpdated(uint256 oldFee, uint256 newFee);
event ProtocolPaused(address operator);
event ProtocolUnpaused(address operator);
// Integration events
event AssetsDeployedToYield(uint256 indexed vaultId, address indexed asset, uint256 amount, address adapter);
event CollateralPositionCreated(uint256 indexed vaultId, uint256 indexed positionId, address protocol);
event AssetsStaked(uint256 indexed vaultId, address indexed asset, uint256 amount, uint256 poolId, uint256 stakeId);Monitoring Example (ethers.js)
// Set up event listener for vault creation
vaultinator.on("VaultCreated", (vaultId, owner, name, vaultType, event) => {
console.log(`New vault created: ${vaultId}`);
console.log(`Owner: ${owner}`);
console.log(`Name: ${name}`);
console.log(`Type: ${vaultType === 0 ? "Personal" : vaultType === 1 ? "Shared" : "Institutional"}`);
// Update UI or database
});
// Set up event listener for deposits
vaultinator.on("Deposited", (vaultId, asset, amount, depositor, event) => {
console.log(`Deposit to vault ${vaultId}: ${ethers.utils.formatEther(amount)} tokens`);
// Update UI or database
});Error Handling
The Vaultinator Facet uses descriptive error messages and custom errors. Handle these appropriately in your integration:
try {
await vaultinator.withdraw(vaultId, daiToken, withdrawAmount);
} catch (error) {
// Extract error message
const errorMessage = error.message;
if (errorMessage.includes("Insufficient balance")) {
console.error("Vault doesn't have enough balance to withdraw this amount");
} else if (errorMessage.includes("Not authorized")) {
console.error("You don't have permission to withdraw from this vault");
} else {
console.error("Unknown error:", errorMessage);
}
}Security Best Practices
When integrating with the Vaultinator Facet, follow these security best practices:
Access Control: Implement proper access control in your application to match the vault's access control system
Input Validation: Validate all user inputs before sending transactions
Transaction Monitoring: Monitor transaction status and handle failures gracefully
Error Handling: Implement comprehensive error handling for all interactions
Emergency Handling: Implement procedures for handling protocol emergencies, such as when the protocol is paused
Gas Optimization
When integrating with the Vaultinator Facet, consider these gas optimization techniques:
Batch Operations: Use batch functions where available to reduce the number of transactions
Gas Price Management: Set appropriate gas prices based on network conditions
State Caching: Cache on-chain state in your application to reduce view function calls
Optimistic UI Updates: Update your UI optimistically while waiting for transaction confirmation
Advanced Integration Patterns
1. Vault Strategy Integration
// Create a custom vault strategy
const strategyAddress = "0x..."; // Address of your strategy contract
// Set vault strategy
await vaultinator.setVaultStrategy(vaultId, strategyAddress);
// Update vault configuration for the strategy
const configData = ethers.utils.defaultAbiCoder.encode(
["uint256", "uint256", "bool"],
[
ethers.utils.parseEther("0.5"), // 50% allocation
86400, // 1 day rebalance period
true // Auto-compound enabled
]
);
await vaultinator.updateVaultConfig(vaultId, configData);2. Multi-Signature Vault Management
// For vaults requiring multiple signatures, use a multi-sig wallet
const multiSigWallet = new ethers.Contract(multiSigAddress, MultiSigABI, signer);
// Create transaction data for vault operation
const data = vaultinator.interface.encodeFunctionData("withdraw", [
vaultId,
daiToken,
withdrawAmount
]);
// Submit transaction to multi-sig
await multiSigWallet.submitTransaction(vaultinatorAddress, 0, data);
// Other signers can confirm the transaction
await multiSigWallet.confirmTransaction(transactionId);
// Once enough confirmations are received, the transaction can be executed
await multiSigWallet.executeTransaction(transactionId);3. Vault Analytics Integration
// Get all vault assets
const assets = await vaultinator.getVaultAssets(vaultId);
// Calculate total value
let totalValueUSD = ethers.BigNumber.from(0);
for (const asset of assets) {
// Get asset price from oracle
const assetPrice = await priceOracle.getPrice(asset.token);
// Calculate value
const assetValue = asset.balance.mul(assetPrice).div(ethers.utils.parseEther("1"));
totalValueUSD = totalValueUSD.add(assetValue);
console.log(`Asset: ${asset.token}`);
console.log(`Balance: ${ethers.utils.formatUnits(asset.balance, asset.decimals)}`);
console.log(`Value (USD): ${ethers.utils.formatUnits(assetValue, 18)}`);
}
console.log(`Total Vault Value (USD): ${ethers.utils.formatUnits(totalValueUSD, 18)}`);