Integration Guides
Comprehensive step-by-step tutorials for integrating zkVault into your application. From basic vault creation to advanced cross-chain deployment.
Creating Your First Vault
Complete walkthrough from wallet connection to encrypted content upload
Managing Beneficiaries
Add, update, and configure beneficiary shares and permissions
Check-in Workflows
Implement automated check-ins and deadman switch monitoring
Cross-Chain Deployment
Deploy and sync vaults across multiple blockchain networks
Attestation Network Setup
Configure decentralized attestation agents for vault verification
Notification Integration
Set up Push Protocol, XMTP, Telegram, and email notifications
Storage Configuration
Integrate Arweave, IPFS, and Ceramic for content storage
Gas Optimization
Best practices for minimizing transaction costs across networks
Creating Your First Vault
Step 1: Install and Initialize SDK
npm install @vault-protocol/sdk ethers
import { VaultProtocolSDK } from '@vault-protocol/sdk';
import { ethers } from 'ethers';
// Connect wallet
const provider = new ethers.providers.Web3Provider(window.ethereum);
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
// Initialize SDK
const sdk = new VaultProtocolSDK({
provider,
signer,
network: 'opbnb',
apiUrl: 'https://api.vaultprotocol.ai',
litNetwork: 'datil-test',
});Step 2: Configure Vault Settings
const vaultConfig = {
name: "My Crypto Inheritance Vault",
releaseType: "DEADMAN", // or "SCHEDULED", "HYBRID"
checkInPeriod: 90 * 24 * 60 * 60, // 90 days in seconds
recipients: [
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", // Beneficiary 1
"0x1234567890abcdef1234567890abcdef12345678" // Beneficiary 2
],
encrypted: true,
metadata: {
description: "Emergency wallet recovery for family",
tags: ["inheritance", "emergency", "family"]
}
};Tip: Use DEADMAN for emergency recovery, SCHEDULED for time-locked releases, HYBRID for both conditions.
Step 3: Create Vault
try {
const vault = await sdk.vaultManager.createVault(vaultConfig);
console.log('✓ Vault created successfully!');
console.log('Vault ID:', vault.id);
console.log('Transaction Hash:', vault.transactionHash);
console.log('Created At:', new Date(vault.createdAt * 1000));
// Store vault ID for future reference
localStorage.setItem('vaultId', vault.id);
} catch (error) {
console.error('Vault creation failed:', error.message);
}Step 4: Upload Encrypted Content
// Prepare sensitive content (e.g., seed phrase)
const seedPhrase = "word1 word2 word3 ... word24";
// Upload with encryption
const contentCID = await sdk.vaultManager.uploadContent(vault.id, {
data: seedPhrase,
encrypted: true,
storageLocation: 'arweave', // Permanent storage
contentType: 'text/plain',
metadata: {
walletType: 'BIP39',
description: 'Main wallet seed phrase',
createdAt: Date.now()
}
});
console.log('✓ Content uploaded and encrypted');
console.log('Content CID:', contentCID);
// For JSON data (wallet configurations, private keys, etc.)
const walletConfig = {
mainWallet: { address: '0x...', privateKey: 'encrypted...' },
subWallets: [...]
};
const jsonCID = await sdk.vaultManager.uploadContent(vault.id, {
data: JSON.stringify(walletConfig, null, 2),
encrypted: true,
storageLocation: 'arweave',
contentType: 'application/json'
});Step 5: Set Up Deadman Switch
await sdk.timeManager.configureDeadmanSwitch(
vault.id,
90 * 24 * 60 * 60, // Check-in period: 90 days
7 * 24 * 60 * 60 // Grace period: 7 days after trigger
);
// Perform initial check-in
await sdk.timeManager.checkIn(vault.id);
console.log('✓ Deadman switch configured');
console.log('Next check-in due: 90 days from now');Managing Beneficiaries
Update Beneficiary Shares
// Define beneficiaries with percentage shares
const beneficiaries = [
{ address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", share: 50 }, // 50%
{ address: "0x1234567890abcdef1234567890abcdef12345678", share: 30 }, // 30%
{ address: "0xabcdef1234567890abcdef1234567890abcdef12", share: 20 } // 20%
];
// Update vault beneficiaries
await sdk.vaultManager.updateBeneficiaries(
vaultId,
beneficiaries.map(b => b.address),
beneficiaries.map(b => b.share * 100) // Convert to basis points
);
console.log('✓ Beneficiaries updated');Note: Shares must total 100%. Use basis points internally (10000 = 100%).
Add Emergency Contact
// Get current vault
const vault = await sdk.vaultManager.getVault(vaultId);
// Add new beneficiary (e.g., trusted friend for emergency)
const updatedBeneficiaries = [
...vault.beneficiaries,
{
address: "0xnewbeneficiary...",
share: 1000 // 10%
}
];
// Adjust existing shares proportionally
const totalNewShares = updatedBeneficiaries.reduce((sum, b) => sum + b.share, 0);
const normalizedBeneficiaries = updatedBeneficiaries.map(b => ({
address: b.address,
share: Math.floor((b.share / totalNewShares) * 10000)
}));
await sdk.vaultManager.updateBeneficiaries(
vaultId,
normalizedBeneficiaries.map(b => b.address),
normalizedBeneficiaries.map(b => b.share)
);Check-in Workflows
Manual Check-in
async function performCheckIn(vaultId) {
try {
await sdk.timeManager.checkIn(vaultId);
const vault = await sdk.vaultManager.getVault(vaultId);
const nextCheckInTime = vault.lastCheckIn + vault.checkInPeriod;
const nextCheckInDate = new Date(nextCheckInTime * 1000);
console.log('✓ Check-in successful');
console.log('Next check-in due:', nextCheckInDate.toLocaleString());
return { success: true, nextCheckInDate };
} catch (error) {
console.error('Check-in failed:', error.message);
return { success: false, error };
}
}Automated Check-in System
// Option 1: Client-side interval (not recommended for production)
function setupAutoCheckIn(vaultId) {
const intervalId = setInterval(async () => {
await sdk.timeManager.checkIn(vaultId);
console.log('Automatic check-in performed');
}, 30 * 24 * 60 * 60 * 1000); // Every 30 days
return () => clearInterval(intervalId);
}
// Option 2: Server-side cron job (recommended)
// In your backend:
import cron from 'node-cron';
// Run daily at 9 AM
cron.schedule('0 9 * * *', async () => {
const vaults = await getVaultsNeedingCheckIn();
for (const vault of vaults) {
try {
await sdk.timeManager.checkIn(vault.id);
await notifyOwner(vault.owner, 'Check-in successful');
} catch (error) {
await notifyOwner(vault.owner, 'Check-in failed', error);
}
}
});
// Option 3: Chainlink Automation (fully decentralized)
// See smart contract integration guide for Chainlink Keepers setupCheck-in Reminders
async function checkAndNotify(vaultId) {
const vault = await sdk.vaultManager.getVault(vaultId);
const now = Math.floor(Date.now() / 1000);
const timeSinceLastCheckIn = now - vault.lastCheckIn;
const timeUntilTrigger = vault.checkInPeriod - timeSinceLastCheckIn;
// Send reminder at 7 days before trigger
if (timeUntilTrigger <= 7 * 24 * 60 * 60 && timeUntilTrigger > 0) {
const daysRemaining = Math.floor(timeUntilTrigger / (24 * 60 * 60));
await sendNotification({
to: vault.owner,
title: "⚠️ Check-in Reminder",
message: `Your vault "${vault.name}" needs check-in in ${daysRemaining} days`,
priority: "high",
actions: [
{ label: "Check In Now", url: `https://app.vaultprotocol.ai/vault/${vaultId}/checkin` }
]
});
}
}Cross-Chain Deployment
Deploy to Multiple Chains
import { ChainId } from '@vault-protocol/sdk';
// Deploy vault to opBNB, Ethereum, and Polygon
const deployment = await sdk.crossChainClient.deployVaultCrossChain(
{
name: "Multi-Chain Inheritance Vault",
releaseType: "DEADMAN",
checkInPeriod: 90 * 24 * 60 * 60,
recipients: ["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"],
encrypted: true
},
[ChainId.OPBNB, ChainId.ETHEREUM, ChainId.POLYGON]
);
console.log('Primary vault (opBNB):', deployment.primaryVaultId);
// Monitor deployment status
deployment.crossChainVaults.forEach(vault => {
console.log(`Chain ${vault.chainId}: ${vault.status}`);
console.log(` Vault ID: ${vault.vaultId}`);
console.log(` Transaction: ${vault.transactionHash}`);
});Sync Vault State Across Chains
// Perform check-in on primary chain (opBNB)
await sdk.timeManager.checkIn(vaultId);
// Sync to other chains via LayerZero
await sdk.crossChainClient.syncVaultState(
vaultId,
ChainId.ETHEREUM
);
await sdk.crossChainClient.syncVaultState(
vaultId,
ChainId.POLYGON
);
console.log('✓ Vault state synced across all chains');
// Verify sync
const ethereumVault = await sdk.vaultManager.getVault(vaultId, {
chainId: ChainId.ETHEREUM
});
console.log('Ethereum last check-in:', ethereumVault.lastCheckIn);Notification Integration
Push Protocol Setup
import * as PushAPI from '@pushprotocol/restapi';
// Initialize Push Protocol
const pushUser = await PushAPI.user.create({
account: userAddress,
env: 'prod'
});
// Subscribe to vault notifications
await PushAPI.channels.subscribe({
signer,
channelAddress: 'eip155:1:0xVaultProtocolChannel',
userAddress,
env: 'prod'
});
// Send notification on vault trigger
async function notifyVaultTrigger(vaultId, vault) {
await PushAPI.payloads.sendNotification({
signer,
type: 1, // Broadcast
identityType: 2, // Direct payload
notification: {
title: "🔓 Vault Triggered",
body: `Your vault "${vault.name}" has been triggered and is ready for unlock.`
},
payload: {
title: "Vault Triggered",
body: `Vault "${vault.name}" (ID: ${vaultId}) has been triggered.`,
cta: `https://app.vaultprotocol.ai/vault/${vaultId}`,
img: ''
},
channel: 'eip155:1:0xVaultProtocolChannel',
env: 'prod'
});
}Telegram Bot Integration
// Backend: Telegram bot setup
import TelegramBot from 'node-telegram-bot-api';
const bot = new TelegramBot(process.env.TELEGRAM_BOT_TOKEN, { polling: true });
// Link wallet to Telegram
bot.onText(/\/start (.+)/, async (msg, match) => {
const chatId = msg.chat.id;
const walletAddress = match[1];
await linkWalletToTelegram(walletAddress, chatId);
bot.sendMessage(chatId, '✓ Wallet linked! You will receive vault notifications here.');
});
// Send vault notification
async function sendTelegramNotification(vaultOwner, message) {
const chatId = await getTelegramChatId(vaultOwner);
if (chatId) {
await bot.sendMessage(chatId, message, {
reply_markup: {
inline_keyboard: [[
{ text: '🔍 View Vault', url: `https://app.vaultprotocol.ai/vault/${vaultId}` },
{ text: '✅ Check In', callback_data: `checkin_${vaultId}` }
]]
}
});
}
}Storage Configuration
Arweave (Permanent Storage)
// Best for: Seed phrases, private keys, critical documents
const arweaveCID = await sdk.vaultManager.uploadContent(vaultId, {
data: seedPhrase,
encrypted: true,
storageLocation: 'arweave',
contentType: 'text/plain'
});
// Pros: Permanent, immutable, one-time fee
// Cons: Higher upfront cost (~$0.50-5 per MB)IPFS (Temporary Storage)
// Best for: Metadata, non-critical data, frequent updates
const ipfsCID = await sdk.vaultManager.uploadContent(vaultId, {
data: vaultMetadata,
encrypted: false,
storageLocation: 'ipfs',
contentType: 'application/json'
});
// Pros: Fast, cheap, easy updates
// Cons: Requires pinning, not permanent by default
// Recommendation: Use with Pinata or Infura pinning serviceCeramic (Dynamic Data)
// Best for: Vault metadata, beneficiary lists, check-in logs
const ceramicStreamId = await sdk.vaultManager.uploadContent(vaultId, {
data: {
beneficiaries: [...],
checkInHistory: [...],
lastUpdated: Date.now()
},
encrypted: false,
storageLocation: 'ceramic',
contentType: 'application/json'
});
// Pros: Mutable, version-controlled, decentralized
// Cons: Requires DID authentication, slightly slowerGas Optimization Tips
Choose the Right Network
Batch Operations
// ❌ Bad: Multiple transactions
for (const vaultId of vaultIds) {
await sdk.timeManager.checkIn(vaultId); // Separate tx for each
}
// ✅ Good: Single batched transaction
await sdk.timeManager.batchCheckIn(vaultIds); // One tx for all
// Gas savings: ~60% for 5+ vaultsUse VaultFactory
// ❌ Bad: Direct deployment (~500K gas) const vault = await vaultContract.deploy(...); // ✅ Good: Factory pattern (~50K gas, 90% savings) const vault = await vaultFactory.deployVault(...);
Off-Chain Data Storage
// ❌ Bad: Store large data on-chain await vaultManager.setContent(vaultId, largeJSONString); // Cost: ~$50-500 on Ethereum // ✅ Good: Store CID only const cid = await uploadToArweave(largeJSONString); await vaultManager.setContentCID(vaultId, cid); // Cost: ~$0.50-5 one-time + minimal gas