Skip to main content

Code Examples — ethers.js v6

Complete TypeScript examples using ethers.js v6 for interacting with Emerald Vault contracts.

Setup

import { ethers } from "ethers";
import vaultAbi from "./abi/EmeraldVault.json";

const provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com");
const signer = new ethers.Wallet("0x...", provider);

const VAULT_ADDRESS = "0x...";
const TOKEN_ADDRESS = "0x...";

const vault = new ethers.Contract(VAULT_ADDRESS, vaultAbi, signer);
const token = new ethers.Contract(
TOKEN_ADDRESS,
[
"function approve(address,uint256) returns (bool)",
"function allowance(address,address) view returns (uint256)",
"function balanceOf(address) view returns (uint256)",
],
signer
);

Read Vault State

const [totalAssets, paused, shareBalance] = await Promise.all([
vault.totalAssets(),
vault.paused(),
vault.balanceOf(signer.address),
]);

console.log({
totalAssets: totalAssets.toString(),
paused,
shareBalance: shareBalance.toString(),
});

Deposit

const amount = ethers.parseUnits("1000", 6); // 1000 USDC

// 1. Check allowance
const allowance = await token.allowance(signer.address, VAULT_ADDRESS);

// 2. Approve if needed
if (allowance < amount) {
const approveTx = await token.approve(VAULT_ADDRESS, amount);
await approveTx.wait();
}

// 3. Deposit
const depositTx = await vault.deposit(amount, signer.address, PARTNER_ID); // (assets, receiver, partnerId)
const receipt = await depositTx.wait();
console.log("Deposit tx:", receipt.hash);

Request Withdrawal

// Shares follow the asset's decimals (this USDC vault → 6).
// Use requestWithdrawal(shares, partnerId) to attribute to a partner.
const shares = ethers.parseUnits("500", 6);
const requestTx = await vault.requestWithdrawal(shares);
const receipt = await requestTx.wait();
console.log("Withdrawal requested:", receipt.hash);

Claim Withdrawal

// claimWithdrawal() takes NO argument — settles your request when it is at the
// FIFO head and the vault is liquid (else reverts NotAtQueueHead / InsufficientLiquidity).
const claimTx = await vault.claimWithdrawal();
await claimTx.wait();
console.log("Withdrawal claimed");

Cancel Withdrawal

const requestIndex = 0;
const cancelTx = await vault.cancelWithdrawal(requestIndex);
await cancelTx.wait();
console.log("Withdrawal cancelled");

Check Withdrawal Status

const [user, shares, assetsOwed, timestamp, claimed, cancelled] =
await vault.getWithdrawalRequest(0);

// assetsOwed is computed live (0 once resolved). Status is queued/claimed/
// cancelled — no time-based claimable/expired state.
let status: string;
if (cancelled) status = "cancelled";
else if (claimed) status = "claimed";
else status = "queued";

console.log({ user, shares: shares.toString(), assetsOwed: assetsOwed.toString(), status });

Get All User Requests

const indices = await vault.getUserRequests(signer.address);

for (const index of indices) {
const [user, shares, assetsOwed, timestamp, claimed, cancelled] =
await vault.getWithdrawalRequest(index);

console.log({ index: index.toString(), shares: shares.toString(), claimed, cancelled });
}

Listen for Events

// Real-time deposit listener
vault.on("Deposit", (sender, owner, assets, shares) => {
console.log("New deposit:", {
sender,
owner,
assets: assets.toString(),
shares: shares.toString(),
});
});

// Query historical events
const filter = vault.filters.WithdrawalRequested(signer.address);
const events = await vault.queryFilter(filter, -10000); // last 10k blocks
for (const event of events) {
console.log("Withdrawal:", event.args);
}

Error Handling

try {
const tx = await vault.deposit(amount, signer.address);
await tx.wait();
} catch (err: any) {
// Decode custom errors
if (err.data) {
const iface = new ethers.Interface(vaultAbi);
try {
const decoded = iface.parseError(err.data);
console.error(`Contract error: ${decoded?.name}`);
// e.g., "EnforcedPause", etc.
} catch {
console.error("Unknown error:", err.message);
}
}
}