Skip to main content

How the Vault Works

The PoolVault is an ERC-4626 vault. You deposit USDC and receive pool shares in return. Shares represent your proportional claim on the pool’s total assets. The pool is the counterparty to every trader position:
  • Trader losses flow into the pool, increasing share price
  • Trader profits are paid from the pool, decreasing share price
  • Trading fees accrue to the pool on every position open
Over time, if the pool collects more in fees and trader losses than it pays in trader profits, the share price increases and your shares become worth more USDC than you deposited.

Share Price

sharePrice = totalAssets / totalSupply
TermDescription
totalAssetsUSDC held by the vault (6 decimals)
totalSupplyPool shares outstanding (6 decimals)
Onchain: both values are stored in the PoolVault contract. See Share Price for the full formula including unrealized PnL adjustments.

Deposit USDC

Depositing requires two transactions: approve the PoolVault to spend your USDC, then call deposit.
1

Approve USDC spending

import { createPublicClient, createWalletClient, http, parseUnits } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
import { mockUsdcAbi } from "@nile-markets/sdk";

const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");

const publicClient = createPublicClient({
  chain: sepolia,
  transport: http("YOUR_RPC_URL"),
});

const walletClient = createWalletClient({
  account,
  chain: sepolia,
  transport: http("YOUR_RPC_URL"),
});

const USDC = "0x...";        // See Contract Addresses page
const POOL_VAULT = "0x...";   // See Contract Addresses page

const amount = parseUnits("1000", 6); // 1,000 USDC

const approveHash = await walletClient.writeContract({
  address: USDC,
  abi: mockUsdcAbi,
  functionName: "approve",
  args: [POOL_VAULT, amount],
});

await publicClient.waitForTransactionReceipt({ hash: approveHash });
console.log("USDC approved for PoolVault");
2

Deposit into the vault

import { poolVaultAbi } from "@nile-markets/sdk";
import { parseUnits, formatUnits } from "viem";

const POOL_VAULT = "0x..."; // See Contract Addresses page
const amount = parseUnits("1000", 6); // 1,000 USDC

const depositHash = await walletClient.writeContract({
  address: POOL_VAULT,
  abi: poolVaultAbi,
  functionName: "deposit",
  args: [amount, account.address], // assets, receiver
});

const receipt = await publicClient.waitForTransactionReceipt({ hash: depositHash });
console.log(`Deposited in tx: ${receipt.transactionHash}`);
Check how many shares you received:
const shares = await publicClient.readContract({
  address: POOL_VAULT,
  abi: poolVaultAbi,
  functionName: "balanceOf",
  args: [account.address],
});

console.log(`Your shares: ${formatUnits(shares, 6)}`);
The number of shares you receive depends on the current share price. If the share price is 1.05, depositing 1,000 USDC yields approximately 952.38 shares (1000 / 1.05).

Preview Deposit

Before depositing, you can preview how many shares you will receive:
import { poolVaultAbi } from "@nile-markets/sdk";
import { parseUnits, formatUnits } from "viem";

const POOL_VAULT = "0x..."; // See Contract Addresses page

const previewShares = await publicClient.readContract({
  address: POOL_VAULT,
  abi: poolVaultAbi,
  functionName: "previewDeposit",
  args: [parseUnits("1000", 6)],
});

console.log(`1,000 USDC → ${formatUnits(previewShares, 6)} shares`);

Withdraw USDC

You can withdraw by specifying either a USDC amount (withdraw) or a share amount (redeem).

Withdraw by USDC Amount

import { poolVaultAbi } from "@nile-markets/sdk";
import { parseUnits } from "viem";

const POOL_VAULT = "0x..."; // See Contract Addresses page
const amount = parseUnits("500", 6); // 500 USDC

const withdrawHash = await walletClient.writeContract({
  address: POOL_VAULT,
  abi: poolVaultAbi,
  functionName: "withdraw",
  args: [amount, account.address, account.address], // assets, receiver, owner
});

await publicClient.waitForTransactionReceipt({ hash: withdrawHash });
console.log("Withdrawn 500 USDC");

Redeem by Share Amount

To redeem a specific number of shares instead of a USDC amount:
import { poolVaultAbi } from "@nile-markets/sdk";
import { parseUnits } from "viem";

const POOL_VAULT = "0x..."; // See Contract Addresses page
const shares = parseUnits("500", 6); // 500 shares

const redeemHash = await walletClient.writeContract({
  address: POOL_VAULT,
  abi: poolVaultAbi,
  functionName: "redeem",
  args: [shares, account.address, account.address], // shares, receiver, owner
});

await publicClient.waitForTransactionReceipt({ hash: redeemHash });

Check Your LP Position

Query your current share balance and its USDC value:
import { poolVaultAbi } from "@nile-markets/sdk";
import { formatUnits } from "viem";

const POOL_VAULT = "0x..."; // See Contract Addresses page

const [shares, totalAssets, totalSupply] = await Promise.all([
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "balanceOf",
    args: [account.address],
  }),
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "totalAssets",
  }),
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "totalSupply",
  }),
]);

const sharePrice = Number(totalAssets) / Number(totalSupply);
const usdcValue = Number(shares) * sharePrice;

console.log(`Shares: ${formatUnits(shares, 6)}`);
console.log(`Share price: ${sharePrice.toFixed(6)}`);
console.log(`Value: ${(usdcValue / 1e6).toFixed(2)} USDC`);

Withdrawal Restrictions

Withdrawals may be restricted when pool utilization is high.
ConditionEffect
Utilization below capFull withdrawal available
Utilization near capPartial withdrawal — only the amount that keeps utilization below the cap
Utilization at capNo withdrawals until positions close and free up capital
Check the maximum withdrawable amount before submitting:
import { poolVaultAbi } from "@nile-markets/sdk";
import { formatUnits } from "viem";

const POOL_VAULT = "0x..."; // See Contract Addresses page

const [maxWithdraw, utilization] = await Promise.all([
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "maxWithdrawable",
  }),
  publicClient.readContract({
    address: POOL_VAULT,
    abi: poolVaultAbi,
    functionName: "utilization",
  }),
]);

console.log(`Max withdrawable: ${formatUnits(maxWithdraw, 6)} USDC`);
console.log(`Current utilization: ${Number(utilization) / 100}%`);
High utilization means the pool’s capital is backing open trader positions. Withdrawing too much would leave the pool unable to pay trader profits. The utilization cap protects both LPs and traders.

Pool Transaction History

View your deposit and withdrawal history via the subgraph:
{
  vaultEvents(
    where: { account: "0xYOUR_ADDRESS" }
    orderBy: timestamp
    orderDirection: desc
    first: 25
  ) {
    id
    type
    assets
    shares
    timestamp
    txHash
  }
}
Or via CLI:
nile pool transactions

Vault Mechanics

How the ERC-4626 vault manages LP capital and counterparty exposure.

Share Price

Detailed share price formula including unrealized PnL adjustments.

Pool Utilization

Utilization calculation, caps, and impact on withdrawals.

Pool Vault Contract

Full contract reference with all read and write functions.