@nemoprotocol/vaults-sdk
v0.3.1
Published
A TypeScript SDK for interacting with Nemo Vaults on the Sui blockchain
Downloads
785
Maintainers
Readme
Nemo Vaults SDK
A TypeScript SDK for interacting with Nemo Vaults on the Sui blockchain. This SDK provides comprehensive functionality for managing liquidity vaults, including deposits, withdrawals, rebalancing, and administrative operations.
Features
- Vault Management: Create, configure, and manage different types of vaults (Stable, Uncorrelated, Drift)
- Liquidity Operations: Deposit and withdraw liquidity with automatic optimization
- Automated Bots: Built-in reward collection and rebalancing bots
- Administrative Functions: Complete admin interface for vault configuration
- Multi-Protocol Support: Integration with various staking protocols (Haedal, Volo, Aftermath)
- Docker Support: Ready-to-use Docker containers for production deployment
Installation
npm install @nemoprotocol/vaults-sdk
# or
yarn add @nemoprotocol/vaults-sdk
# or
pnpm add @nemoprotocol/vaults-sdkQuick Start
import { Vaults, Admin } from '@nemoprotocol/vaults-sdk';
import { SuiClient } from '@mysten/sui/client';
// Initialize the SDK
const suiClient = new SuiClient({ url: 'https://sui-mainnet.blockvision.org' });
const vaults = Vaults.createSDK({
client: suiClient
});
// Get all vaults
const vaultList = await vaults.getVaultList();
// Get a specific vault
const vault = await vaults.getVault('vault-id');
// Get user's vault balances
const balances = await vaults.getOwnerVaultsBalance('user-address');Core Concepts
Vault Types
- Stable Vaults: Optimized for stable asset pairs with minimal price volatility
- Uncorrelated Vaults: Designed for assets with low correlation, includes rebalancing triggers
- Drift Vaults: Specialized for trending markets with directional price movements
Liquidity Management
- Both-sided deposits: Provide both tokens in optimal ratio
- One-sided deposits: Provide single token with automatic swapping
- Flexible withdrawals: Withdraw as LP tokens or individual assets
- Slippage protection: Configurable slippage tolerance for all operations
Examples
Basic Vault Operations
import { Vaults, Admin, InputType } from '@nemoprotocol/vaults-sdk';
import { SuiClient } from '@mysten/sui/client';
import { Transaction } from '@mysten/sui/transactions';
// Initialize the SDK
const suiClient = new SuiClient({ url: 'https://sui-mainnet.blockvision.org' });
const vaults = Vaults.createSDK({
client: suiClient
});
async function basicVaultOperations() {
try {
// 1. Get all available vaults
console.log('Fetching all vaults...');
const allVaults = await vaults.getVaultList();
console.log(`Found ${allVaults.length} vaults`);
// 2. Get detailed information about a specific vault
const vaultId = allVaults[0].id;
const vault = await vaults.getVault(vaultId);
if (!vault) {
console.error('Vault not found');
return;
}
console.log('Vault details:', {
id: vault.id,
coinTypeA: vault.coin_type_a,
coinTypeB: vault.coin_type_b,
totalSupply: vault.total_supply,
depositEnabled: vault.is_deposit_enabled
});
// 3. Check user's vault balances
const userAddress = 'user-wallet-address';
const userBalances = await vaults.getOwnerVaultsBalance(userAddress);
console.log(`User has positions in ${userBalances.length} vaults`);
// 4. Calculate deposit amount for one-sided deposit
console.log('Calculating deposit amount...');
const depositCalc = await vaults.calculateDepositAmount({
vault_id: vaultId,
is_amount_a: true,
input_amount: '1000000', // 1 token (assuming 6 decimals)
slippage: 0.01, // 1% slippage
side: InputType.OneSide
});
console.log('Deposit calculation result:', {
amountA: depositCalc.amount_a,
amountB: depositCalc.amount_b,
lpTokens: depositCalc.ft_amount,
swapRequired: !!depositCalc.swap_result
});
// 5. Execute deposit transaction
const tx = new Transaction();
const lpToken = await vaults.deposit({
vault_id: vaultId,
slippage: 0.01,
deposit_result: depositCalc,
return_coin: true
}, tx);
console.log('Deposit transaction prepared');
// Note: You would sign and execute the transaction here
} catch (error) {
console.error('Error in vault operations:', error);
}
}Deposit and Withdrawal Operations
async function depositWithdrawExample() {
// Initialize SDK
const suiClient = new SuiClient({ url: 'https://sui-mainnet.blockvision.org' });
const vaults = Vaults.createSDK({
client: suiClient
});
const vaultId = 'your-vault-id';
const slippage = 0.01; // 1% slippage tolerance
try {
// === DEPOSIT OPERATIONS ===
// 1. One-sided deposit (provide only token A)
console.log('Calculating one-sided deposit...');
const oneSidedDeposit = await vaults.calculateDepositAmount({
vault_id: vaultId,
is_amount_a: true,
input_amount: '1000000', // 1 token A (assuming 6 decimals)
slippage,
side: InputType.OneSide
});
console.log('One-sided deposit calculation:', {
inputAmount: oneSidedDeposit.original_input_amount,
amountA: oneSidedDeposit.amount_a,
amountB: oneSidedDeposit.amount_b,
lpTokens: oneSidedDeposit.ft_amount,
swapRequired: !!oneSidedDeposit.swap_result
});
// Execute one-sided deposit
const depositTx = new Transaction();
await vaults.deposit({
vault_id: vaultId,
slippage,
deposit_result: oneSidedDeposit,
return_coin: false // Transfer LP tokens to user
}, depositTx);
console.log('One-sided deposit transaction prepared');
// 2. Both-sided deposit (provide both tokens)
console.log('Calculating both-sided deposit...');
const bothSidedDeposit = await vaults.calculateDepositAmount({
vault_id: vaultId,
is_amount_a: true,
input_amount: '1000000', // 1 token A
slippage,
side: InputType.Both
});
console.log('Both-sided deposit calculation:', {
amountA: bothSidedDeposit.amount_a,
amountB: bothSidedDeposit.amount_b,
lpTokens: bothSidedDeposit.ft_amount
});
// Execute both-sided deposit
const bothDepositTx = new Transaction();
await vaults.deposit({
vault_id: vaultId,
slippage,
deposit_result: bothSidedDeposit,
return_coin: false
}, bothDepositTx);
console.log('Both-sided deposit transaction prepared');
// === WITHDRAWAL OPERATIONS ===
// 1. Both-sided withdrawal (receive both tokens)
console.log('Calculating both-sided withdrawal...');
const bothSidedWithdraw = await vaults.calculateWithdrawAmount({
vault_id: vaultId,
is_amount_a: true,
is_ft_input: true,
input_amount: oneSidedDeposit.ft_amount, // Withdraw all LP tokens
max_ft_amount: oneSidedDeposit.ft_amount,
slippage,
side: InputType.Both
});
console.log('Both-sided withdrawal calculation:', {
burnAmount: bothSidedWithdraw.burn_ft_amount,
receiveA: bothSidedWithdraw.amount_a,
receiveB: bothSidedWithdraw.amount_b
});
// Execute both-sided withdrawal
const withdrawTx = new Transaction();
await vaults.withdraw({
vault_id: vaultId,
ft_amount: bothSidedWithdraw.burn_ft_amount,
slippage,
return_coin: false
}, withdrawTx);
console.log('Both-sided withdrawal transaction prepared');
// 2. One-sided withdrawal (receive only token A)
console.log('Calculating one-sided withdrawal...');
const oneSidedWithdraw = await vaults.calculateWithdrawAmount({
vault_id: vaultId,
is_amount_a: true,
is_ft_input: false,
input_amount: '1000000', // input vault token amount
max_ft_amount: oneSidedDeposit.ft_amount,
slippage,
side: InputType.OneSide
});
console.log('One-sided withdrawal calculation:', {
burnAmount: oneSidedWithdraw.burn_ft_amount,
receiveA: oneSidedWithdraw.amount_a,
receiveB: oneSidedWithdraw.amount_b,
swapRequired: !!oneSidedWithdraw.swap_result
});
// Execute one-sided withdrawal
const oneSideWithdrawTx = new Transaction();
await vaults.withdraw({
vault_id: vaultId,
is_amount_a: true,
is_ft_input: false,
input_amount: '1000000', // input vault token amount
max_ft_amount: oneSidedDeposit.ft_amount,
slippage,
return_coin: false
}, oneSideWithdrawTx);
console.log('One-sided withdrawal transaction prepared');
// === ADVANCED: Using coin objects ===
// Deposit with specific coin objects
const advancedDepositTx = new Transaction();
const coinA = advancedDepositTx.splitCoins(advancedDepositTx.gas, [1000000]);
const coinB = advancedDepositTx.splitCoins(advancedDepositTx.gas, [1000000]);
await vaults.deposit({
vault_id: vaultId,
coin_object_a: coinA,
coin_object_b: coinB,
slippage,
deposit_result: bothSidedDeposit,
return_coin: true // Return LP token object
}, advancedDepositTx);
console.log('Advanced deposit with coin objects prepared');
} catch (error) {
console.error('Error in deposit/withdraw operations:', error);
}
}Administrative Operations
async function adminOperations() {
const admin = Admin.createSDK({
fullNodeUrl: 'https://sui-mainnet.blockvision.org',
senderAddress: 'admin-wallet-address'
});
try {
// Create a new stable vault
const tx = await admin.newStableVault({
pool_id: 'clmm-pool-id',
treasury_cap_id: 'treasury-cap-id',
upper_price_scalling: '1.1', // 10% above current price
lower_price_scalling: '0.9', // 10% below current price
slippage_up: '0.02', // 2% slippage tolerance up
slippage_down: '0.02', // 2% slippage tolerance down
free_threshold_a: '1000000', // 1 token A threshold
free_threshold_b: '1000000', // 1 token B threshold
fee_val: '0.003', // 0.3% fee
withdraw_fee_val: '0.001', // 0.1% withdrawal fee
decimals_a: 6,
decimals_b: 6,
deposit_limit: '1000000000', // 1000 tokens limit
coin_type_a: '0x2::sui::SUI',
coin_type_b: '0x...::usdc::USDC',
coin_type_token: '0x...::lp_token::LP_TOKEN'
});
console.log('Stable vault creation transaction prepared');
// Configure vault settings
const configTx = new Transaction();
await admin.setDepositLimit('vault-id', 'vault-cap', 2000000000n, configTx);
// await admin.setSlippage('risk-admin-cap', 'vault-id', '0.03', '0.03', configTx);
console.log('Vault configuration transaction prepared');
} catch (error) {
console.error('Error in admin operations:', error);
}
}Monitoring Vault Performance
async function monitorVaultPerformance() {
const suiClient = new SuiClient({ url: 'https://sui-mainnet.blockvision.org' });
const vaults = Vaults.createSDK({
client: suiClient
});
const userAddress = 'user-wallet-address';
try {
// Get user's positions across all vaults
const userBalances = await vaults.getOwnerVaultsBalance(userAddress);
console.log(`User has positions in ${userBalances.length} vaults:`);
for (const balance of userBalances) {
console.log(`
Vault: ${balance.vault_id}
LP Token Balance: ${balance.lp_token_balance}
Underlying Token A: ${balance.amount_a} (${balance.coin_type_a})
Underlying Token B: ${balance.amount_b} (${balance.coin_type_b})
Position Range: ${balance.tick_lower_index} to ${balance.tick_upper_index}
`);
}
// Get detailed vault information
for (const balance of userBalances) {
const vault = await vaults.getVault(balance.vault_id);
if (vault) {
console.log(`
Vault ${vault.id} Details:
- Type: ${vault.config_type}
- Total Supply: ${vault.total_supply}
- Deposit Enabled: ${vault.is_deposit_enabled}
- Locked: ${vault.is_lock}
- Fee: ${vault.fee_val}
- Withdraw Fee: ${vault.withdraw_fee_val}
- Last Rebalance: ${new Date(parseInt(vault.last_rebalance_time) * 1000).toISOString()}
`);
}
}
} catch (error) {
console.error('Error monitoring vault performance:', error);
}
}API Reference
Vaults Class
The main class for interacting with vaults.
Creating an Instance
const vaults = Vaults.createSDK({
client: suiClient // SuiClient instance
});
// Or with custom RPC URL
const vaults = Vaults.createSDK({
fullNodeUrl: 'https://custom-rpc-url'
});Core Methods
getVaultList()
Retrieves all available vaults.
const vaults = await sdk.getVaultList();getVault(id: string)
Get detailed information about a specific vault.
const vault = await sdk.getVault('vault-id');getOwnerVaultsBalance(address: string)
Get user's balances across all vaults.
const balances = await sdk.getOwnerVaultsBalance('user-address');getOwnerVaultBalance(address: string, vaultId: string)
Get a user's balance for a specific vault including LP token decimals.
const balance = await sdk.getOwnerVaultBalance('user-address', 'vault-id');getPositionAssets(vaultId: string)
Get position token amounts with current prices and USD values for a specific vault.
const positionAssets = await sdk.getPositionAssets('vault-id');
console.log('Position Assets:', {
amountA: positionAssets.amount_a,
amountB: positionAssets.amount_b,
priceA: positionAssets.price_a,
priceB: positionAssets.price_b,
totalValueUSD: positionAssets.total_value_usd,
lpUsdPrice: positionAssets.lp_usd_price
});getRemainingCap(vaultId: string)
Get remaining deposit capacity for a specific vault.
const remainingCap = await sdk.getRemainingCap('vault-id');
console.log('Remaining Capacity:', {
depositLimitUSD: remainingCap.deposit_limit_usd,
currentPositionValueUSD: remainingCap.current_position_value_usd,
remainingCapUSD: remainingCap.remaining_cap_usd
});getVaultMarketHolders(vaultId?: string)
Get all vault market holders with their aggregated USD values across all vault markets.
const holders = await sdk.getVaultMarketHolders('vault-id');
console.log('Vault Market Holders:', holders);
// Output: [
// { address: '0x123...', usdValue: '100.5000000000000000' },
// { address: '0x456...', usdValue: '210.7500000000000000' }
// ]getVaultStatus()
Get the current status of all vaults including rebalancing status and configuration details.
const vaultStatus = await sdk.getVaultStatus();
console.log('Vault Status:', vaultStatus);
// Output: [
// {
// vaultId: '0x123...',
// isRebalancing: false,
// vaultName: 'SUI-USDC Vault',
// disable: false,
// }
// ]Deposit Operations
calculateDepositAmount(params)
Calculate optimal deposit amounts and required swaps.
const depositCalc = await sdk.calculateDepositAmount({
vault_id: 'vault-id',
is_amount_a: true,
input_amount: '1000000',
slippage: 0.01,
side: InputType.OneSide
});deposit(params, tx)
Execute a deposit transaction.
import { Transaction } from '@mysten/sui/transactions';
const tx = new Transaction();
const result = await sdk.deposit({
vault_id: 'vault-id',
slippage: 0.01,
deposit_result: depositCalc,
return_coin: true
}, tx);Withdrawal Operations
calculateWithdrawAmount(params)
Calculate withdrawal amounts and required swaps.
const withdrawCalc = await sdk.calculateWithdrawAmount({
vault_id: 'vault-id',
is_amount_a: true,
is_ft_input: true,
input_amount: '1000000',
max_ft_amount: '2000000',
slippage: 0.01,
side: InputType.OneSide
});withdraw(params, tx)
Execute a withdrawal transaction.
const tx = new Transaction();
const result = await sdk.withdraw({
vault_id: 'vault-id',
ft_amount: '1000000',
slippage: 0.01,
return_coin: true
}, tx);Admin Class
Administrative functions for vault management.
Creating an Instance
const admin = Admin.createSDK({
fullNodeUrl: 'https://sui-mainnet.blockvision.org',
senderAddress: 'admin-address'
});Vault Creation
newStableVault(params)
Create a new stable vault.
const tx = await admin.newStableVault({
pool_id: 'clmm-pool-id',
treasury_cap_id: 'treasury-cap-id',
upper_price_scalling: '1.1',
lower_price_scalling: '0.9',
slippage_up: '0.01',
slippage_down: '0.01',
free_threshold_a: '1000000',
free_threshold_b: '1000000',
fee_val: '0.003',
withdraw_fee_val: '0.001',
decimals_a: 6,
decimals_b: 6,
deposit_limit: '1000000000',
coin_type_a: 'coin-type-a',
coin_type_b: 'coin-type-b',
coin_type_token: 'lp-token-type'
});newUncorrelatedVault(params)
Create a new uncorrelated vault with rebalancing triggers.
const tx = await admin.newUncorrelatedVault({
// ... similar params as stable vault
lock_threshold_a: '5000000',
lock_threshold_b: '5000000',
target_adapter: 'price-adapter',
is_target_reverse: false
});Vault Configuration
setDepositLimit(vaultId, vaultCap, limit)
Update vault deposit limits.
await admin.setDepositLimit('vault-id', 'vault-cap', 1000000000n, tx);setFee(adminCap, vaultId, feeVal)
Set vault fee percentages.
await admin.setFee('admin-cap', 'vault-id', '0.003', tx);Types and Interfaces
Vault Interface
interface Vault {
id: string;
clmm_pool_id: string;
coin_type_a: string;
coin_type_b: string;
lp_token_type: string;
config_type: string;
total_supply: string;
deposit_limit: string;
is_deposit_enabled: boolean;
is_lock: boolean;
// ... additional properties
}Calculation Parameters
interface CalculateAmountParams {
vault_id: string;
is_amount_a: boolean;
input_amount: string;
slippage: number;
side: InputType;
}
enum InputType {
Both = 'both',
OneSide = 'oneSide'
}Automated Bots
The SDK includes two automated bots for production use:
Reward Bot
Automatically collects and compounds vault rewards.
# Run directly
pnpm run run:reward
# Or with Docker
docker-compose up reward-botRebalance Bot
Monitors and rebalances uncorrelated vaults when price thresholds are reached.
# Run directly
pnpm run run:rebalance
# Or with Docker
docker-compose up rebalance-botEnvironment Configuration
Create a .env file with the following variables:
# Sui Network
SUI_PRIVATE_KEY=your-base64-encoded-private-key
FULL_NODE_URL=https://sui-mainnet.blockvision.org
# Slack Notifications (for bots)
SLACK_TOKEN=xoxb-your-slack-bot-token
SLACK_CONVERSATION_ID=your-channel-id
SLACK_VAULT_REBALANCE_CONVERSATION_ID=rebalance-channel-id
# Optional
NODE_ENV=productionDocker Deployment
The SDK provides ready-to-use Docker containers:
# Build and run both bots
docker-compose up -d
# Run specific bot
docker-compose up -d reward-bot
docker-compose up -d rebalance-bot
# View logs
docker-compose logs -f reward-botSee DOCKER.md for detailed Docker setup instructions.
Error Handling
The SDK uses a comprehensive error handling system:
import { VaultsErrorCode } from '@nemoprotocol/vaults-sdk';
try {
const vault = await vaults.getVault('invalid-id');
} catch (error) {
if (error.code === VaultsErrorCode.ObjectNotFound) {
console.log('Vault not found');
}
}Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
MIT License
Support
For issues and questions:
- Create an issue on GitHub
- Check the API documentation
Development Setup
# Install dependencies
pnpm install
# Build the SDK
pnpm run build
# Run tests
pnpm test
# Build bots
pnpm run build:all