KhipuVault Docs

IndividualPool Contract

Complete reference for IndividualPool smart contract - methods, events, and integration examples.

IndividualPool Contract

IndividualPool is a personal savings contract where users deposit MUSD tokens and earn yields from Mezo protocol integration.

Contract Details

Address (Mezo Testnet): 0xdfBEd2D3efBD2071fD407bF169b5e5533eA90393

Chain ID: 31611 (Mezo Testnet)

Solidity Version: 0.8.26

Inheritance: BasePoolV3 → UUPSUpgradeable → OwnableUpgradeable → ReentrancyGuardUpgradeable

Key Features

  • Personal savings pool (1 user = 1 pool)
  • Flexible deposits and withdrawals
  • Automatic yield calculation from Mezo protocol
  • Optional auto-compounding
  • Upgradeable via UUPS proxy
  • Reentrancy protected

State Variables

contract IndividualPoolV3 {
    IERC20 public musdToken;              // MUSD token address
    address public owner;                 // Pool owner
    uint256 public balance;               // User's balance
    uint256 public totalYield;            // Accumulated yield
    uint256 public lastYieldUpdate;       // Last yield calculation
    bool public autoCompound;             // Auto-compound flag
    uint256 public minimumDeposit;        // Min deposit (10 MUSD)
    uint256 public createdAt;             // Creation timestamp
}

Read Functions

balanceOf

Get user's current balance.

function balanceOf(address account) external view returns (uint256)

Parameters:

  • account (address): User address

Returns:

  • balance (uint256): User's balance in wei

Wagmi Example:

import { useReadContract } from 'wagmi'

const { data: balance } = useReadContract({
  address: '0xdfBEd2D3efBD2071fD407bF169b5e5533eA90393',
  abi: INDIVIDUAL_POOL_ABI,
  functionName: 'balanceOf',
  args: [userAddress]
})

console.log(`Balance: ${formatUnits(balance, 18)} MUSD`)

calculateYield

Calculate pending yield for a user.

function calculateYield(address account) external view returns (uint256)

Returns:

  • Claimable yield in wei

Example:

const { data: yield } = useReadContract({
  address: INDIVIDUAL_POOL_ADDRESS,
  abi: INDIVIDUAL_POOL_ABI,
  functionName: 'calculateYield',
  args: [userAddress]
})

totalDeposits

Get total deposits in pool.

function totalDeposits() external view returns (uint256)

Example:

const { data: total } = useReadContract({
  address: INDIVIDUAL_POOL_ADDRESS,
  abi: INDIVIDUAL_POOL_ABI,
  functionName: 'totalDeposits'
})

getCurrentAPR

Get current Annual Percentage Rate.

function getCurrentAPR() external view returns (uint256)

Returns:

  • APR in basis points (e.g., 1850 = 18.5%)

Write Functions

deposit

Deposit MUSD tokens into the pool.

function deposit(uint256 amount) external nonReentrant

Parameters:

  • amount (uint256): Amount to deposit in wei

Requirements:

  • Amount more than 0
  • Amount at least minimumDeposit (for first deposit)
  • User has approved MUSD spending
  • User has sufficient MUSD balance

Events Emitted:

  • Deposit(address indexed user, uint256 amount, uint256 newBalance, uint256 timestamp)

Wagmi Example:

import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
import { parseUnits } from 'viem'

function DepositButton() {
  const { writeContract, data: hash } = useWriteContract()
  const { isLoading, isSuccess } = useWaitForTransactionReceipt({ hash })

  const handleDeposit = async () => {
    // First, approve MUSD
    await writeContract({
      address: MUSD_ADDRESS,
      abi: MUSD_ABI,
      functionName: 'approve',
      args: [INDIVIDUAL_POOL_ADDRESS, parseUnits('100', 18)]
    })

    // Then deposit
    writeContract({
      address: INDIVIDUAL_POOL_ADDRESS,
      abi: INDIVIDUAL_POOL_ABI,
      functionName: 'deposit',
      args: [parseUnits('100', 18)]
    })
  }

  return <button onClick={handleDeposit}>Deposit 100 MUSD</button>
}

withdraw

Withdraw MUSD tokens from the pool.

function withdraw(uint256 amount) external nonReentrant

Parameters:

  • amount (uint256): Amount to withdraw in wei

Requirements:

  • Amount more than 0
  • Amount at most user balance
  • Pool has sufficient liquidity

Events Emitted:

  • Withdrawal(address indexed user, uint256 amount, uint256 newBalance, uint256 timestamp)

Example:

const { writeContract } = useWriteContract()

const withdraw = () => {
  writeContract({
    address: INDIVIDUAL_POOL_ADDRESS,
    abi: INDIVIDUAL_POOL_ABI,
    functionName: 'withdraw',
    args: [parseUnits('50', 18)]
  })
}

claimYield

Claim accumulated yield.

function claimYield() external nonReentrant returns (uint256)

Returns:

  • Amount of yield claimed

Events Emitted:

  • YieldClaimed(address indexed user, uint256 amount, uint256 timestamp)

Example:

const { writeContract } = useWriteContract()

const claimYield = () => {
  writeContract({
    address: INDIVIDUAL_POOL_ADDRESS,
    abi: INDIVIDUAL_POOL_ABI,
    functionName: 'claimYield'
  })
}

setAutoCompound

Enable or disable automatic yield compounding.

function setAutoCompound(bool enabled) external

Parameters:

  • enabled (bool): True to enable, false to disable

Example:

const { writeContract } = useWriteContract()

const toggleAutoCompound = (enabled: boolean) => {
  writeContract({
    address: INDIVIDUAL_POOL_ADDRESS,
    abi: INDIVIDUAL_POOL_ABI,
    functionName: 'setAutoCompound',
    args: [enabled]
  })
}

Events

Deposit

event Deposit(
    address indexed user,
    uint256 amount,
    uint256 newBalance,
    uint256 timestamp
)

Listening to Events:

import { useWatchContractEvent } from 'wagmi'

useWatchContractEvent({
  address: INDIVIDUAL_POOL_ADDRESS,
  abi: INDIVIDUAL_POOL_ABI,
  eventName: 'Deposit',
  onLogs(logs) {
    logs.forEach(log => {
      console.log('Deposit:', {
        user: log.args.user,
        amount: formatUnits(log.args.amount, 18),
        newBalance: formatUnits(log.args.newBalance, 18)
      })
    })
  }
})

Withdrawal

event Withdrawal(
    address indexed user,
    uint256 amount,
    uint256 newBalance,
    uint256 timestamp
)

YieldClaimed

event YieldClaimed(
    address indexed user,
    uint256 amount,
    uint256 timestamp
)

Complete ABI

export const INDIVIDUAL_POOL_ABI = [
  // Read functions
  {
    name: 'balanceOf',
    type: 'function',
    stateMutability: 'view',
    inputs: [{ name: 'account', type: 'address' }],
    outputs: [{ name: '', type: 'uint256' }]
  },
  {
    name: 'calculateYield',
    type: 'function',
    stateMutability: 'view',
    inputs: [{ name: 'account', type: 'address' }],
    outputs: [{ name: '', type: 'uint256' }]
  },
  {
    name: 'totalDeposits',
    type: 'function',
    stateMutability: 'view',
    inputs: [],
    outputs: [{ name: '', type: 'uint256' }]
  },
  {
    name: 'getCurrentAPR',
    type: 'function',
    stateMutability: 'view',
    inputs: [],
    outputs: [{ name: '', type: 'uint256' }]
  },
  // Write functions
  {
    name: 'deposit',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [{ name: 'amount', type: 'uint256' }],
    outputs: []
  },
  {
    name: 'withdraw',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [{ name: 'amount', type: 'uint256' }],
    outputs: []
  },
  {
    name: 'claimYield',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [],
    outputs: [{ name: '', type: 'uint256' }]
  },
  {
    name: 'setAutoCompound',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [{ name: 'enabled', type: 'bool' }],
    outputs: []
  },
  // Events
  {
    name: 'Deposit',
    type: 'event',
    inputs: [
      { name: 'user', type: 'address', indexed: true },
      { name: 'amount', type: 'uint256', indexed: false },
      { name: 'newBalance', type: 'uint256', indexed: false },
      { name: 'timestamp', type: 'uint256', indexed: false }
    ]
  },
  {
    name: 'Withdrawal',
    type: 'event',
    inputs: [
      { name: 'user', type: 'address', indexed: true },
      { name: 'amount', type: 'uint256', indexed: false },
      { name: 'newBalance', type: 'uint256', indexed: false },
      { name: 'timestamp', type: 'uint256', indexed: false }
    ]
  },
  {
    name: 'YieldClaimed',
    type: 'event',
    inputs: [
      { name: 'user', type: 'address', indexed: true },
      { name: 'amount', type: 'uint256', indexed: false },
      { name: 'timestamp', type: 'uint256', indexed: false }
    ]
  }
] as const

Gas Estimates

FunctionGas (avg)Gas (max)
deposit65,00085,000
withdraw55,00075,000
claimYield45,00060,000
setAutoCompound35,00045,000

Security Features

  • ✅ Reentrancy guard on all state-changing functions
  • ✅ SafeERC20 for token transfers
  • ✅ Checks-Effects-Interactions pattern
  • ✅ Upgradeable (UUPS) with access control
  • ✅ Audited by [Auditor Name]

Next Steps

On this page