Supply to a Pool

Enable a user to supply assets into a Teller ERC4626 pool.

Addresses you’ll need per pool

  • asset: ERC20 you deposit (e.g. WBTC)

  • vault: Teller Pool (ERC4626 vault mints/burns shares)

The following code example is in typescript. These smart contract integrations can be generalized to any codebase.

Minimal ABIs

// ERC20 (approve/allowance/balanceOf/decimals)
export const erc20Abi = [
  { type:'function', name:'decimals', stateMutability:'view', inputs:[], outputs:[{type:'uint8'}]},
  { type:'function', name:'balanceOf', stateMutability:'view', inputs:[{type:'address'}], outputs:[{type:'uint256'}]},
  { type:'function', name:'allowance', stateMutability:'view', inputs:[{type:'address'},{type:'address'}], outputs:[{type:'uint256'}]},
  { type:'function', name:'approve', stateMutability:'nonpayable', inputs:[{type:'address'},{type:'uint256'}], outputs:[{type:'bool'}]},
] as const;

// ERC4626 (deposit/redeem/convertToAssets/balanceOf)
export const erc4626Abi = [
  { type:'function', name:'deposit',  stateMutability:'nonpayable', inputs:[{type:'uint256','name':'assets'},{type:'address','name':'receiver'}], outputs:[{type:'uint256'}] },
  { type:'function', name:'redeem',   stateMutability:'nonpayable', inputs:[{type:'uint256','name':'shares'},{type:'address','name':'receiver'},{type:'address','name':'owner'}], outputs:[{type:'uint256'}] },
  { type:'function', name:'convertToAssets', stateMutability:'view', inputs:[{type:'uint256','name':'shares'}], outputs:[{type:'uint256'}]},
  { type:'function', name:'balanceOf', stateMutability:'view', inputs:[{type:'address'}], outputs:[{type:'uint256'}]},
] as const;

SUPPLY (approve asset → vault.deposit)

import { useAccount } from 'wagmi';
import { parseUnits } from 'viem';

export async function supply({
  client, // wagmi config or public client via useWriteContract
  account,
  asset,
  vault,
  amountStr,       // e.g. "100"
  assetDecimals,   // read once and cache
}: {
  client: any;
  account: `0x${string}`;
  asset: `0x${string}`;
  vault: `0x${string}`;
  amountStr: string;
  assetDecimals: number;
}) {
  const amount = parseUnits(amountStr, assetDecimals);

  // 1) Check allowance; approve if needed (exact, or +1.1x if you prefer a cushion)
  const current = await client.readContract({
    address: asset, abi: erc20Abi, functionName: 'allowance',
    args: [account, vault],
  }) as bigint;

  if (current < amount) {
    await client.writeContract({
      address: asset, abi: erc20Abi, functionName: 'approve',
      args: [vault, amount], // or Math.ceil(amount * 1.1n) if you want 10% cushion
    });
  }

  // 2) Deposit assets → receive shares
  await client.writeContract({
    address: vault, abi: erc4626Abi, functionName: 'deposit',
    args: [amount, account],
  });
}

READS for UI: balances

Supplied in Teller pool (shares held, not staked)

export async function readVaultBalances({ client, vault, user }:{
  client:any; vault:`0x${string}`; user:`0x${string}`;
}) {
  const shares = await client.readContract({
    address: vault, abi: erc4626Abi, functionName: 'balanceOf', args: [user],
  }) as bigint;

  const assets = await client.readContract({
    address: vault, abi: erc4626Abi, functionName: 'convertToAssets', args: [shares],
  }) as bigint;

  return { shares, assets }; // shares in vault token decimals; assets in underlying decimals
}

Last updated