Create a seamless yield-earning experience with Privy’s embedded wallets and Morpho’s vaults. This guide shows you how to build a Next.js app where users can approve, deposit, check balances, and withdraw USDC with yield—all without external wallets or complex onboarding.

Resources


Getting started with Privy

If you have not set up Privy yet, start by following the Privy React quickstart guide to integrate Privy’s authentication and wallet functionality. Optionally, after completing the React quickstart, integrate viem by following the viem integration guide.

Using Morpho Vaults with Privy

Morpho vaults are smart contracts that let users earn yield by depositing assets into automated, yield-optimizing pools. Now we’ll integrate Morpho vaults into the app.

Configure and deposit into a Morpho vault

Morpho offers multiple vaults, each with different strategies and underlying assets. You can discover vaults on the Morpho App or via the Morpho API. For this example, we’ll use the Steakhouse USDC Vault on Base:
1

1. Configure the vault

const MORPHO_VAULT_ADDRESS = '0xbeeF010f9cb27031ad51e3333f9aF9C6B1228183';
const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const BASE_CHAIN_ID = 8453;
2

2. Approve the vault to spend USDC

Use viem’s encodeFunctionData to encode the approval, and Privy’s useSendTransaction to send it:
import {encodeFunctionData, maxUint256, erc20Abi} from 'viem';
import {useSendTransaction} from '@privy-io/react-auth';

const {sendTransaction} = useSendTransaction();

const data = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'approve',
  args: [MORPHO_VAULT_ADDRESS as `0x${string}`, maxUint256]
});

const tx = await sendTransaction({
  to: USDC_ADDRESS as `0x${string}`,
  data,
  chainId: BASE_CHAIN_ID
});
3

3. Deposit USDC into the Vault

Use viem to encode the deposit and Privy’s useSendTransaction to fund the vault:
import {encodeFunctionData, parseUnits, parseAbi} from 'viem';
import {useSendTransaction} from '@privy-io/react-auth';

const {sendTransaction} = useSendTransaction();

const vaultAbi = parseAbi([
  'function deposit(uint256 assets, address receiver) external returns (uint256 shares)'
]);
const depositAmount = parseUnits('100', 6); // 100 USDC
const data = encodeFunctionData({
  abi: vaultAbi,
  functionName: 'deposit',
  args: [depositAmount, address]
});

const tx = await sendTransaction({
  to: MORPHO_VAULT_ADDRESS as `0x${string}`,
  data,
  chainId: BASE_CHAIN_ID
});

Read the vault share balance

Query the vault’s balanceOf function to determine how much the user can withdraw.
import {publicClient} from './viem';
import {parseAbi} from 'viem';

const balanceAbi = parseAbi([
  'function balanceOf(address account) external view returns (uint256)'
]);

const userShares = await publicClient.readContract({
  address: MORPHO_VAULT_ADDRESS as `0x${string}`,
  abi: balanceAbi,
  functionName: 'balanceOf',
  args: [address]
});

Withdraw from the Vault

Users have options to withdraw a specific amount of USDC or redeem all shares (full exit).
import {encodeFunctionData, parseUnits, parseAbi} from 'viem';
import {useSendTransaction} from '@privy-io/react-auth';

const {sendTransaction} = useSendTransaction();

const withdrawAbi = parseAbi([
  'function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares)'
]);
const withdrawAmount = parseUnits('50', 6); // 50 USDC
const data = encodeFunctionData({
  abi: withdrawAbi,
  functionName: 'withdraw',
  args: [withdrawAmount, address, address]
});
const tx = await sendTransaction({
  to: MORPHO_VAULT_ADDRESS as `0x${string}`,
  data,
  chainId: BASE_CHAIN_ID
});

Get real-time vault data

You can fetch live vault information using Morpho’s GraphQL API:
const fetchVaultData = async () => {
  const query = `
    query {
      vaultByAddress(
        address: "${MORPHO_VAULT_ADDRESS}"
        chainId: ${BASE_CHAIN_ID}
      ) {
        state {
          sharePriceUsd
          apy
        }
        asset {
          priceUsd
        }
      }
    }
  `;
  const response = await fetch('https://api.morpho.org/graphql', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({query})
  });
  return response.json();
};

Key integration tips

  1. Always approve first: Users need ERC-20 approval before any deposit.
  2. Use deposit() and redeem(): These cover most use cases effectively.
  3. Handle decimals correctly: USDC uses 6 decimals, vault shares use 18.
  4. Check liquidity: During high utilization, withdrawals may be limited.
  5. Monitor gas: Complex vaults may require more gas for transactions.

Conclusion

With Privy, setting up secure, user-friendly access to Morpho contracts is fast and easy. For advanced use cases, refer to the Morpho Docs, or reach out to us in Slack
Your app is now ready to interact with Morpho using Privy embedded wallets!