Documentation Index Fetch the complete documentation index at: https://mintlify.com/Rohit-KK15/MetaVault-AI/llms.txt
Use this file to discover all available pages before exploring further.
The Chat Agent is a user-friendly assistant that helps MetaVault users interact with the vault, check balances, deposit, withdraw, and access public information while maintaining strict privacy and security boundaries.
Overview
export const chatAgent = new LlmAgent ({
name: "chat_agent" ,
description: "A user-friendly assistant for MetaVault users to interact with the MetaVault, check balances, deposit, withdraw, and get public information." ,
model: model ,
tools: [
get_user_vault_balance ,
get_wallet_link_balance ,
get_public_vault_info ,
check_allowance ,
approve_link ,
user_deposit ,
user_withdraw ,
get_token_prices ,
get_vault_apy ,
convert_to_shares ,
convert_to_assets
]
});
Source: packages/agents/defi-portfolio/src/agents/sub-agents/chat-agent/agent.ts:18-145
Security & Privacy Rules
The Chat Agent enforces strict security boundaries:
Can ONLY access data for the user who is asking (using their wallet address)
NEVER exposes confidential information:
Strategy internals (leverage ratios, debt positions)
Admin-only functions (rebalance, harvest, update parameters)
Other users’ balances or private data
Liquidation or risk calculations (admin-only)
May ONLY reply using public vault information:
Total vault assets
APY
Token prices
User’s own balance and shares
Source: agent.ts:28-39
Gets the current user’s vault share balance and withdrawable LINK amount. Schema: z . object ({
userAddress: z . string (). describe ( "The user's wallet address" )
})
Implementation: export const get_user_vault_balance = createTool ({
name: "get_my_balance" ,
description: "Gets the current user's vault share balance and withdrawable LINK amount. Only returns data for the requesting user." ,
fn : async ({ userAddress }) => {
const [ balance , assets ] = await Promise . all ([
chain_read ( env . VAULT_ADDRESS , VaultABI . abi , "balanceOf" , [ userAddress ]),
chain_read ( env . VAULT_ADDRESS , VaultABI . abi , "convertToAssets" , [
await chain_read ( env . VAULT_ADDRESS , VaultABI . abi , "balanceOf" , [ userAddress ])
])
]);
return {
raw: { shares: balance . toString (), withdrawable: assets . toString () },
human: { shares: format18 ( balance ), withdrawable: format18 ( assets ) }
};
}
});
Source: tools.ts:17-46Returns: User’s vault shares and withdrawable LINK amount (raw and human-readable)
Returns the user’s LINK balance in their wallet. Schema: z . object ({
wallet: z . string (). describe ( "The user's wallet address" )
})
Implementation: export const get_wallet_link_balance = createTool ({
name: "get_link_balance" ,
description: "Returns the user's LINK balance in their wallet." ,
fn : async ({ wallet }) => {
const rawBalance = await chain_read (
env . LINK_ADDRESS ,
MockERC20ABI . abi ,
"balanceOf" ,
[ wallet ]
);
return {
wallet ,
rawBalance: rawBalance . toString (),
balance: format18 ( rawBalance ),
symbol: "LINK" ,
message: `The wallet ${ wallet } has ${ format18 ( rawBalance ) } LINK.`
};
}
});
Source: tools.ts:48-78Returns: LINK balance in user’s wallet
Prepares an unsigned LINK deposit transaction for the user to sign in their wallet. Schema: z . object ({
amount: z . string (). describe ( "Amount of LINK to deposit" )
})
Implementation: export const user_deposit = createTool ({
name: "user_deposit" ,
description: "Prepares an unsigned LINK deposit transaction for the user to sign in their wallet." ,
fn : async ({ amount }) => {
const parsedAmount = parseUnits ( amount );
const iface = new ethers . Interface ( VaultABI . abi );
const data = iface . encodeFunctionData ( "deposit" , [ parsedAmount ]);
return {
success: true ,
unsignedTx: {
to: env . VAULT_ADDRESS ,
data ,
value: "0"
},
message: `Please sign this deposit transaction for ${ amount } LINK.`
};
}
});
Source: tools.ts:170-195Returns: Unsigned transaction object for user to sign
Withdraws shares from the vault for the user. Schema: z . object ({
shares: z . string (). describe ( "Number of shares to withdraw (in human-readable format)" )
})
Implementation: export const user_withdraw = createTool ({
name: "user_withdraw" ,
description: "Withdraws shares from the vault for the user. Returns transaction hash." ,
fn : async ({ shares }) => {
const parsedAmount = parseUnits ( shares );
const iface = new ethers . Interface ( VaultABI . abi );
const data = iface . encodeFunctionData ( "withdraw" , [ parsedAmount ]);
return {
success: true ,
unsignedTx: {
to: env . VAULT_ADDRESS ,
data ,
value: "0"
},
message: `Please sign this withdraw transaction for ${ shares } LINK.`
};
}
});
Source: tools.ts:201-224Returns: Unsigned transaction object for user to sign
Converts LINK amount to Vault Share Tokens (VST). Schema: z . object ({
amount: z . string (). describe ( "The amount of LINK (in Human Readable Format)" )
})
Implementation: export const convert_to_shares = createTool ({
name: "convert_to_shares" ,
description: "To convert LINK amount to Vault Share Tokens(VST)." ,
fn : async ({ amount }) => {
const shares = await chain_read (
env . VAULT_ADDRESS ,
VaultABI . abi ,
"convertToShares" ,
[ parseUnits ( amount )]
);
return format18 ( shares );
}
});
Source: tools.ts:270-286Returns: Equivalent VST shares for given LINK amount
Converts Vault Share Tokens (VST) to LINK. Schema: z . object ({
shares: z . string (). describe ( "The amount of shares or VST (in Human Readable Format)" )
})
Implementation: export const convert_to_assets = createTool ({
name: "convert_to_assets" ,
description: "To convert Vault Share Tokens(VST) to LINK." ,
fn : async ({ shares }) => {
const linkAmount = await chain_read (
env . VAULT_ADDRESS ,
VaultABI . abi ,
"convertToAssets" ,
[ parseUnits ( shares )]
);
return format18 ( linkAmount );
}
});
Source: tools.ts:288-304Returns: Equivalent LINK amount for given VST shares
Gets public vault information including total managed assets and total supply. Implementation: export const get_public_vault_info = createTool ({
name: "get_public_vault_info" ,
description: "Gets public vault information including total managed assets and total supply. This is public information available to all users." ,
fn : async () => {
const [ totalManaged , totalSupply ] = await Promise . all ([
chain_read ( env . VAULT_ADDRESS , VaultABI . abi , "totalManagedAssets" , []),
chain_read ( env . VAULT_ADDRESS , VaultABI . abi , "totalSupply" , []),
]);
return {
raw: { totalManaged: totalManaged . toString (), totalSupply: totalSupply . toString () },
human: { totalManaged: format18 ( totalManaged ), totalSupply: format18 ( totalSupply ) }
};
}
});
Source: tools.ts:83-107Returns: Total managed assets and total supply (public data)
Fetches real-time LINK price from CoinGecko API. Implementation: export const get_token_prices = createTool ({
name: "get_token_prices" ,
description: "Fetches real-time LINK price from CoinGecko API. Returns public market prices." ,
fn : async () => {
const response = await fetch (
"https://api.coingecko.com/api/v3/simple/price?ids=chainlink,weth&vs_currencies=usd&include_24hr_change=true"
);
const data = await response . json ();
const linkPriceUSD = data . chainlink ?. usd ;
const link24hChange = data . chainlink ?. usd_24h_change ;
return {
raw: { linkPriceUSD: BigInt ( Math . floor ( linkPriceUSD * 1e18 )). toString () },
human: {
linkPriceUSD: linkPriceUSD . toFixed ( 2 ),
link24hChange: link24hChange . toFixed ( 2 ) + "%"
},
source: "CoinGecko API"
};
}
});
Source: tools.ts:229-268Returns: Current LINK price in USD and 24h price change
Gets the current vault APY based on TVL growth. Implementation: import { calculateVaultAPY } from "../strategy-sentinel-agent/tools" ;
export const get_vault_apy = createTool ({
name: "get_vault_apy" ,
description: "Gets the current vault APY based on TVL growth. This is public information." ,
fn : async ( _params : {}, toolContext : ToolContext ) => {
return calculateVaultAPY ( toolContext );
}
});
Source: tools.ts:309-317Note: Reuses APY calculation logic from Strategy Sentinel AgentReturns: Current vault APY percentage
Checks if user’s LINK token allowance is enough for a deposit. Schema: z . object ({
wallet: z . string (),
amount: z . string ()
})
Implementation: export const check_allowance = createTool ({
name: "check_allowance" ,
description: "Checks if user's LINK token allowance is enough for a deposit." ,
fn : async ({ wallet , amount }) => {
const needed = parseUnits ( amount );
const allowance = await chain_read (
env . LINK_ADDRESS ,
MockERC20ABI . abi ,
"allowance" ,
[ wallet , env . VAULT_ADDRESS ]
);
return {
allowance: allowance . toString (),
enough: allowance >= needed ,
needed: needed . toString (),
wallet
};
}
});
Source: tools.ts:109-135Returns: Whether allowance is sufficient and amounts
Prepares an unsigned approval transaction so the vault can spend LINK. Schema: z . object ({
amount: z . string ()
})
Implementation: export const approve_link = createTool ({
name: "approve_link" ,
description: "Prepares an unsigned approval transaction so the vault can spend LINK." ,
fn : async ({ amount }) => {
const iface = new ethers . Interface ( MockERC20ABI . abi );
const data = iface . encodeFunctionData ( "approve" , [
env . VAULT_ADDRESS ,
parseUnits ( amount )
]);
return {
unsignedTx: {
to: env . LINK_ADDRESS ,
data ,
value: "0"
},
message: `Please sign this transaction to approve ${ amount } LINK for spending.`
};
}
});
Source: tools.ts:137-163Returns: Unsigned approval transaction for user to sign
Communication Style
The Chat Agent follows specific formatting rules:
No Markdown, HTML, or special symbols (asterisks, underscores, backticks)
Use clear line breaks, indentation, and emojis for structure
Round numbers to 2 decimal points when displaying (NOT for transactions)
Be friendly, simple, and helpful
Explain what the user needs to sign (Approval or Deposit)
Source: agent.ts:23-26
Transaction Logic
Deposit Flow
When a user asks to deposit:
Step 1: Call check_allowance(wallet, amount)
Step 2A: If allowance is insufficient:
Call approve_link(amount)
Respond telling user they must first sign the approval transaction
After user signs approval, call user_deposit(amount)
Step 2B: If allowance is already enough:
Call user_deposit(amount) directly
Prepare deposit transaction
Source: agent.ts:67-75
Withdraw Flow
When a user asks to withdraw:
Call user_withdraw(shares) directly
No approval needed for withdrawals
Source: agent.ts:77-78
When using tools for DEPOSIT, WITHDRAW, APPROVAL, or CHECK_ALLOWANCE, the agent MUST return only valid JSON:
{
"reply" : "<text response to user>" ,
"unsignedTx" : < null OR unsigned transaction object> ,
"needsApproval" : < true | false OR null > ,
"step" : "<approval | deposit | withdrawal | info>"
}
Fields:
reply: Human-friendly message
unsignedTx: Transaction user must sign (or null)
needsApproval: true only when approval is required
step: One of “approval”, “deposit”, “withdrawal”, or “info”
Source: agent.ts:103-124
Restrictions
If user asks about admin operations, the agent responds:
“I can help with deposits, withdrawals, balances, and public data. Strategy management is restricted to vault administrators.”
Admin operations include:
rebalance
harvest
risk parameters
Source: agent.ts:84-90
Example Interactions
Deposit with Approval
User: "Deposit 10 LINK"
Agent:
1. check_allowance(wallet, "10")
2. If allowance = 0:
- approve_link("10")
- Return: {
"reply": "Please sign this approval transaction to allow the vault to spend 10 LINK.",
"unsignedTx": { to: LINK_ADDRESS, data: "...", value: "0" },
"needsApproval": true,
"step": "approval"
}
3. After user signs approval:
- user_deposit("10")
- Return: {
"reply": "Please sign this deposit transaction for 10 LINK.",
"unsignedTx": { to: VAULT_ADDRESS, data: "...", value: "0" },
"needsApproval": false,
"step": "deposit"
}
Source: agent.ts:92-102
Check Balance
User: "What's my balance?"
Agent:
1. get_my_balance(userAddress)
2. Return: {
"reply": "You have 123.45 LINK in shares, which you can withdraw as 125.67 LINK.",
"unsignedTx": null,
"needsApproval": null,
"step": "info"
}
Withdraw
User: "Withdraw 50 shares"
Agent:
1. user_withdraw("50")
2. Return: {
"reply": "Please sign this withdraw transaction for 50 shares.",
"unsignedTx": { to: VAULT_ADDRESS, data: "...", value: "0" },
"needsApproval": false,
"step": "withdrawal"
}
Responsibilities Summary
The Chat Agent must:
User Assistance - Help users deposit, withdraw, or check vault information
Address Verification - Always ask for wallet address when accessing personal data
Approval Management - Determine whether user needs approval transaction before deposit
Transaction Preparation - Produce unsigned transactions for the wallet to sign
Privacy Protection - Never expose admin functions or internal vault strategy logic
Source: agent.ts:59-90